Warum sollte man MACRO+0 !=0 verwenden

Lesezeit: 6 Minuten

In meiner aktuellen Codebasis sehe ich folgendes Muster:

#if SOMETHING_SUPPORTED+0 != 0
...
#endif

Leider ist dies eine sehr alte Codebasis und niemand weiß, wie und warum es angefangen hat. Ich glaube, es begann in C und wurde langsam mit Klassen in C umgewandelt und jetzt tendiert es zu C++

Ich sehe keinen offensichtlichen Vorteil darin, das vorherige Konstrukt anstelle des “Klassikers” zu verwenden, aber vielleicht fehlt mir etwas:

#if SOMETHING_SUPPORTED
...
#endif

Weißt du, warum würde man verwenden #if MACRO+0 != 0 Anstatt von #if MACRO?

  • Könnte verwandt sein: Test auf leere Makrodefinition

    – t.niese

    5. Mai 2016 um 10:22 Uhr

  • Das != 0 ist sicher überflüssig

    – MM

    5. Mai 2016 um 10:30 Uhr

Benutzeravatar von Kaz
Kaz

Der Hinweis hier ist, dass die Codebasis sehr alt ist.

Dieser Trick existiert wahrscheinlich, weil der Code einmal auf einen Compiler mit einem sehr alten Präprozessor portiert wurde, der nicht behandelt wird nicht definiert Makros als 0 im Präprozessor #if Bedingungen.

Das heißt, ab 1989 ANSI C wurde standardisiert, dass, wenn wir haben:

#if foo + bar – xyzzy

Die Direktive unterliegt der Makroersetzung, sodass if foo, bar oder xyzzy Makros sind, werden sie ersetzt. Dann werden alle verbleibenden Bezeichner, die nicht ersetzt wurden, durch ersetzt 0. Also wenn foo ist definiert als 42aber bar und xyzzy überhaupt nicht definiert sind, erhalten wir:

#if 42 + 0 - 0

und nicht, sagen wir, schlechte Syntax:

#if 42 + -

oder ein anderes Verhalten, wie Diagnosen über bar nicht definiert.

Auf einem Präprozessor, wo undefinierte Makros als Leerzeichen behandelt werden, #if SOMETHING_SUPPORTED erweitert sich auf gerade #ifwas dann falsch ist.

Dies ist die einzige Möglichkeit, dies zu tun IDENT+0 Trick macht wirklich Sinn. Sie würden dies einfach niemals tun wollen, wenn Sie sich darauf verlassen können, dass die Vorverarbeitung ISO-C-konform ist.

Der Grund ist, dass wenn SOMETHING_SUPPORTED Numerische Werte erwartet werden, ist es irrtümlich unsinnig, es einfach als Leerzeichen zu definieren. Idealerweise möchten Sie feststellen, wann dies geschehen ist, und die Kompilierung mit einer Diagnose stoppen.

Zweitens, wenn Sie tun Wenn Sie eine solche verwirrende Verwendung unterstützen, möchten Sie mit ziemlicher Sicherheit, dass sich ein explizit definiertes, aber leeres Symbol so verhält, als hätte es den Wert 1 und nicht den Wert 0. Andernfalls erstellen Sie eine Falle. Jemand könnte dies auf der Compiler-Befehlszeile tun:

 -DSOMETHING_SUPPORTED=$SHELL_VAR  # oops, SHELL_VAR expanded to nothing

oder im Code:

 #define SOMETHING_SUPPORTED  /* oops, forgot "1" */

Niemand wird es tun hinzufügen a #define oder -D für ein Symbol mit der Absicht, sich zu drehen aus die Funktion, die es steuert! Der Programmierer, der a einfügt #define SOMETHING_SUPPORTED ohne das 1 wird durch das Verhalten von überrascht sein

 #if SOMETHING_SUPPORTED+0

wodurch das Material übersprungen wird, das aktiviert werden sollte.

Aus diesem Grund vermute ich, dass nur wenige C-Programmierer, die dies lesen, jemals eine solche Verwendung gesehen haben, und warum ich vermute, dass es sich nur um eine Problemumgehung für das Verhalten des Präprozessors handelt, dessen beabsichtigter Effekt darin besteht, den Block if zu überspringen SOMETHING_SUPPORTED wird vermisst. Die Tatsache, dass es eine “Programmiererfalle” legt, ist nur ein Nebeneffekt der Problemumgehung.

Um ein solches Präprozessorproblem zu umgehen, ohne eine Programmierfalle zu erstellen, muss man irgendwo früh in der Übersetzungseinheit Folgendes haben:

#ifndef SOMETHING_SUPPORTED
#define SOMETHING_SUPPORTED 0
#endif

und dann woanders einfach verwenden #if SOMETHING_SUPPORTED. Vielleicht ist dieser Ansatz dem ursprünglichen Programmierer nicht in den Sinn gekommen, oder vielleicht hat dieser Programmierer das gedacht +0 trick war ordentlich und legte Wert auf seine Geschlossenheit.

  • Du liegst nicht falsch, aber … alle Unixy-Compiler, die ich kenne, behandeln -DTHING als Abkürzung für -DTHING=1; Wenn Sie tatsächlich möchten, dass das Makro zu nichts erweitert wird, müssen Sie dies sagen -DTHING=.

    – zol

    5. Mai 2016 um 18:26 Uhr

  • @zwol Könnte übrigens passieren -DFOO=$FOO_ON, wobei die Shell-Variable auf nichts erweitert wurde, anstatt wie erwartet auf 0 oder 1! (bearbeitet).

    – Kas

    5. Mai 2016 um 18:31 Uhr


  • @zwol In der Tat. Dies liegt wahrscheinlich daran, dass Build-Skripte auf einen einzelnen Anwendungsfall zugeschnitten sind, ständig mit fast denselben Eingaben arbeiten und ihre Logik daher auf das erwartete Verhalten dieses Anwendungsfalls ausgerichtet ist. (Nicht anders als die wegwerfbaren Skripte, die Leute für ihren eigenen Gebrauch schreiben, oder vielleicht sogar noch schlimmer).

    – Kas

    5. Mai 2016 um 21:25 Uhr

Benutzeravatar von MM
MM

#if X+0 != 0 ist anders als #if X in dem Fall wo X als leer definiert ist (Hinweis: Dies ist anders als im Fall von X nicht definiert), zB:

#define X

#if X          // error
#if X+0 != 0   // no error; test fails

Es ist sehr üblich, leere Makros zu definieren: Die Projektkonfiguration kann einen gemeinsamen Header generieren, der eine Reihe von Zeilen enthält #define USE_FOO, #define USE_BAR Funktionen zu aktivieren, die das System unterstützt, und so weiter.

Das != 0 ist überflüssig, der Code hätte einfach sein können #if X+0.


Also, der Vorteil der Verwendung #if X+0 ist das wenn X als leer definiert ist, wird die Kompilierung mit dem übersprungenen Block fortgesetzt, anstatt einen Fehler auszulösen.

Ob das eine gute Idee ist, darüber lässt sich streiten, würde ich persönlich nutzen #ifdef für boolesche Makros wie USE_SOME_FEATUREund #if für Makros, bei denen der Wert beispielsweise ein Bereich von ganzen Zahlen sein kann; und ich möchte einen Fehler sehen, wenn ich versehentlich verwende #if mit etwas, das auf leer definiert ist.

  • Eine Flagge wie -DNDEBUG wird definieren NDEBUG sein 1nicht leer.

    – Dietrich Ep

    5. Mai 2016 um 11:21 Uhr

  • @DietrichEpp du hast recht. -DNEBUG= würde es als leer definieren

    – MM

    5. Mai 2016 um 11:33 Uhr

  • Ich habe noch nie einen Fehler von diesem gesehen. Das #if wertet nach meiner Erfahrung einfach zu false aus (was wahrscheinlich immer noch nicht erwünscht ist). EDIT: Ich stehe korrigiert, dies erzeugt tatsächlich einen Fehler. Ich bin mir nicht sicher, was ich in der Vergangenheit gesehen hatte. Vielleicht war es Compiler-spezifisch.

    – Kamerun

    5. Mai 2016 um 13:23 Uhr


  • @MM Zur Erinnerung: Es ist jedoch unmöglich, das Allzweck-Leerheitsdetektor-Makro zu erstellen. Hinweis: Es gibt einige “nahezu” Implementierungen. Hier ist eines von ihnen.

    – pmor

    15. September um 19:06 Uhr


Benutzeravatar von John Zwinck
Johannes Zwinck

Machen wir einen Tisch!

X       #if X     #if X+0 != 0
<undef> false     false
<empty> error     false
0       false     false
1       true      true
2       true      true
a       false     false
xyz     false     false
12a     error     error
12 a    error     error

Der einzige Unterschied, den wir (dank der Kommentatoren) gefunden haben, ist der Fall, in dem X definiert ist, aber keinen Wert hat (wie eine leere Zeichenfolge). Ich habe die noch nie gesehen +0 != 0 Variante vor.

  • @MM: Das dachte ich mir auch. Ich teste es einfach. Es funktioniert wie erwartet. Also habe ich meine Antwort als falsch gelöscht.

    – Martin York

    5. Mai 2016 um 10:34 Uhr

  • @MM: Nein, ist es nicht. stackoverflow.com/questions/1643820/…

    – Dietrich Ep

    5. Mai 2016 um 10:38 Uhr

  • @DietrichEpp, bei dieser Frage geht es um X undefiniert, nicht um X leer. Ich denke, die Tabelle in dieser Antwort sollte “leer” in “undefiniert” umbenennen und eine neue Zeile für “leer” hinzufügen.

    – MM

    5. Mai 2016 um 11:05 Uhr


  • @LokiAstari vielleicht hast du etwas falsch gemacht, siehe hier

    – MM

    5. Mai 2016 um 11:05 Uhr

  • Sie können andere Nichtübereinstimmungen finden, wenn Sie die Operator-Vorrangregeln missbrauchen, zum Beispiel mit #define X 1^2.

    – Ilmari Karonen

    5. Mai 2016 um 15:33 Uhr

Benutzeravatar von user207421
Benutzer207421

Es ist eine andere Art zu schreiben

 #if defined(MACRO) && MACRO != 0

Das +0 ist da, um sicherzustellen, dass das Ergebnis eine Zahl ist. Wenn MACRO nicht definiert ist, vermeidet es den Syntaxfehler, der daraus resultieren würde #if MACRO != 0.

Zeug von schlechter Qualität, aber leg dich nicht damit an, es sei denn, du musst.

1416910cookie-checkWarum sollte man MACRO+0 !=0 verwenden

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy