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 sie begonnen hat. Ich denke, es hat in C angefangen und es wurde langsam mit Klassen in C konvertiert und jetzt tendiert es zu C ++
Ich kann keinen offensichtlichen Vorteil der Verwendung des vorherigen Konstrukts anstelle des "Klassikers" erkennen, aber vielleicht fehlt mir etwas:
#if SOMETHING_SUPPORTED
...
#endif
Wissen Sie, warum man #if MACRO+0 != 0
statt verwenden sollte #if MACRO
?
!= 0
ist sicherlich überflüssigAntworten:
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 undefinierte Makros in Präprozessorbedingungen nicht als 0 behandelt
#if
.Das heißt, ab 1989 ANSI C wurde standardisiert, dass, wenn wir haben:
#if foo + bar - xyzzy
die Richtlinie unterliegt Makro - Ersatz, dass dann , wenn er
foo
,bar
oderxyzzy
Makros sind, sie ersetzt werden. Dann werden alle verbleibenden Bezeichner, die nicht ersetzt wurden, durch ersetzt0
. Wennfoo
also definiert ist als42
, aberbar
undxyzzy
überhaupt nicht definiert sind, erhalten wir:#if 42 + 0 - 0
und nicht zum Beispiel schlechte Syntax:
#if 42 + -
oder ein anderes Verhalten, wie die Diagnose, dass es
bar
nicht definiert wurde.Auf einem Präprozessor, bei dem undefinierte Makros als Leerzeichen behandelt werden, wird
#if SOMETHING_SUPPORTED
auf just erweitert#if
, was dann fehlerhaft ist.Nur so
IDENT+0
macht dieser Trick wirklich Sinn. Sie würden dies einfach nie tun wollen, wenn Sie sich darauf verlassen können, dass die Vorverarbeitung ISO C-konform ist.Der Grund dafür ist, dass, wenn
SOMETHING_SUPPORTED
erwartet wird, dass sie numerische Werte haben, es fälschlicherweise verstreut ist, sie einfach als Leerzeichen zu definieren. Idealerweise möchten Sie erkennen, wann dies geschehen ist, und die Kompilierung mit einer Diagnose beenden.Zweitens, wenn Sie tun , eine solche Streu-brained Nutzung unterstützen Sie mit ziemlicher Sicherheit ein explizit definiert, aber leere Symbol zu verhalten , als ob es den Wert 1 hatte, nicht den Wert 0. Ansonsten sind Sie eine Falle zu schaffen. Jemand könnte dies in 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 ein oder für ein Symbol hinzufügen , um die von ihm gesteuerte Funktion auszuschalten ! Der Programmierer, der ein ohne das einfügt, wird vom Verhalten von überrascht sein
#define
-D
#define SOMETHING_SUPPORTED
1
#if SOMETHING_SUPPORTED+0
Dadurch wird das Material übersprungen, das aktiviert werden sollte.
Aus diesem Grund vermute ich, dass nur wenige C-Programmierer, die dies lesen, jemals eine solche Verwendung gesehen haben, und ich vermute, dass dies nur eine Problemumgehung für das Verhalten des Präprozessors ist, dessen beabsichtigter Effekt darin besteht, den Block zu überspringen, wenn er
SOMETHING_SUPPORTED
fehlt. Die Tatsache, dass es sich um eine "Programmierfalle" handelt, ist nur ein Nebeneffekt der Problemumgehung.Um ein solches Präprozessorproblem zu umgehen, ohne eine Programmierfalle zu erstellen, muss irgendwo in der Übersetzungseinheit Folgendes vorhanden sein:
#ifndef SOMETHING_SUPPORTED #define SOMETHING_SUPPORTED 0 #endif
und dann woanders einfach benutzen
#if SOMETHING_SUPPORTED
. Vielleicht kam dieser Ansatz dem ursprünglichen Programmierer nicht in den Sinn, oder vielleicht hielt dieser Programmierer diesen+0
Trick für ordentlich und legte Wert auf seine Selbstbeherrschung.quelle
-DTHING
als Abkürzung behandelt werden-DTHING=1
; Wenn Sie tatsächlich möchten, dass das Makro zu nichts erweitert wird, müssen Sie dies sagen-DTHING=
.-DFOO=$FOO_ON
, wenn die Shell- Variable wie erwartet auf nichts anstatt auf 0 oder 1 erweitert wird! (bearbeitet).#if X+0 != 0
unterscheidet sich von#if X
dem Fall, inX
dem leer definiert ist (Hinweis: Dies unterscheidet sich von dem Fall, dass esX
nicht definiert ist), z.#define X #if X // error #if X+0 != 0 // no error; test fails
Es ist sehr üblich, leere Makros zu definieren: Die Projektkonfiguration generiert möglicherweise einen allgemeinen Header, der eine Reihe von Zeilen enthält
#define USE_FOO
,#define USE_BAR
um vom System unterstützte Funktionen zu aktivieren usw.Das
!= 0
ist redundant, der Code hätte einfach sein können#if X+0
.Der Vorteil der Verwendung
#if X+0
besteht also darin, dass dieX
Kompilierung fortgesetzt wird, wenn sie als leer definiert ist, wobei der Block übersprungen wird, anstatt einen Fehler auszulösen.Ob dies eine gute Idee ist, ist umstritten. Ich persönlich würde sie
#ifdef
für boolesche Makros wieUSE_SOME_FEATURE
und#if
für Makros verwenden, bei denen der Wert beispielsweise eine Reihe von Ganzzahlen sein kann. und ich möchte einen Fehler sehen, wenn ich versehentlich#if
etwas verwende, das als leer definiert ist.quelle
-DNDEBUG
wird definiertNDEBUG
zu sein1
, nicht leer ist .-DNEBUG=
würde es als leer definieren#if
meiner Erfahrung nach nur als falsch bewertet (was wahrscheinlich immer noch nicht erwünscht ist). EDIT: Ich stehe korrigiert da, dies erzeugt tatsächlich einen Fehler. Ich bin mir nicht sicher, was ich in der Vergangenheit gesehen hatte. Vielleicht war es compilerspezifisch.Lass uns einen Tisch machen!
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 Kommentatoren) festgestellt haben, ist der Fall, in dem X definiert ist, aber keinen Wert hat (wie eine leere Zeichenfolge). Ich habe die
+0 != 0
Variante noch nie gesehen .quelle
#define X 1^2
.Es ist eine andere Art zu schreiben
#if defined(MACRO) && MACRO != 0
Die +0 ist da, um sicherzustellen, dass das Ergebnis eine Zahl ist. Wenn
MACRO
nicht definiert, wird der Syntaxfehler vermieden, der sich daraus ergeben würde#if MACRO != 0
.Zeug von schlechter Qualität, aber leg dich nicht damit an, es sei denn du musst.
quelle
#if MACRO+0 !=0
keine andere Schreibweise ist#if defined(MACRO) && MACRO != 0
. Beispiel:#define MACRO
würde zu einem Buildfehler für führen#if defined(MACRO) && MACRO != 0
und würde gut kompilieren für#if MACRO+0 !=0
#define MACRO
OP-Code kompiliert, Ihre Version jedoch nicht