Makrovergleich der If-Direktive

25

Warum ist die #ifBedingung im folgenden Code erfüllt:

#include <iostream>
#define VALUE foo    

int main() {    
#if VALUE == bar
    std::cout << "WORKS!" << std::endl;
#endif // VALUE
}
michalt38
quelle

Antworten:

26

Auf der Seite auf cppreference.com heißt es:

Nach allen Makroerweiterungen und Auswertungen definierter und __has_include (seit C ++ 17) Ausdrücke wird jeder Bezeichner, der kein boolesches Literal ist, durch die Zahl 0 ersetzt (dies schließt Bezeichner ein, die lexikalisch Schlüsselwörter sind, aber keine alternativen Token wie und ).

Also beide foound barwerden durch 0 ersetzt.

BessieTheCow
quelle
Was ist mit C ++ 98, C ++ 03, C ++ 11 und C ++ 14?
Kelalaka
1
@kelalaka Es ist alles das gleiche. Seit C89 ist das so.
SS Anne
1
@kelalaka Das "seit C ++ 17" bezieht sich nur auf den Teil "und __has_include". Vor C ++ 17 war es dasselbe, nur dass dieser Teil weggelassen wurde.
BessieTheCow
15

In einer #ifAnweisung wird jeder nach der Makrosubstitution verbleibende Bezeichner (mit Ausnahme von trueund false) durch die Konstante ersetzt 0. So wird Ihre Direktive

#if 0 == 0

was wahr ist.

1201Programmalarm
quelle
Zur Verdeutlichung definiert '#define VALUE foo' das Symbol 'VALUE', das auf den gleichen Wert wie das Symbol 'foo' aufgelöst werden soll, aber das Symbol 'foo' hat keine Bedeutung und wird daher als 0 interpretiert.
ManicDee
14

Dies liegt daran , weder foonoch bareine Definition oder Wert angegeben wurde - so sie gleich sind (dh mit einem Wert „0“ ersetzt). Compiler geben hierzu Warnungen aus.

Der MSVCCompiler (Visual Studio 2019) bietet Folgendes:

Warnung C4668: 'foo' ist nicht als Präprozessor-Makro definiert und wird durch '0' für '# if / # elif' ersetzt.
Warnung C4668: 'bar' ist nicht als Präprozessor-Makro definiert und wird durch '0' für '#if' ersetzt / # elif '

Erhält VALUEalso den Wert '0' (Standard für foo) und barhat auch '0', ergibt also VALUE == bar"TRUE".

In ähnlicher Weise clang-clergibt sich Folgendes:

Warnung: 'foo' ist nicht definiert, ergibt 0 [-Wundef]
Warnung: 'bar' ist nicht definiert, ergibt 0 [-Wundef]

Adrian Mole
quelle
Ist die Warnung obligatorisch oder ist sie eine Funktion der Compiler?
Kelalaka
1
@kelalaka Nach meinem besten Wissen sind keine Compiler-Warnungen obligatorisch! Auch mit der MSVCund clang-clCompiler kann diese Warnung deaktiviert werden (entweder ausdrücklich oder durch eine entsprechende Warnung ‚Ebene‘ gesetzt wird ).
Adrian Mole
0

Versuchen Sie Folgendes, um das zu erreichen, wonach Sie suchen:

#include <iostream>
#define DEBUG  

int main() {    
#ifdef DEBUG
    std::cout << "WORKS!" << std::endl;
#endif
}

In diesem Fall können Sie die Debugging-Anweisungen deaktivieren, indem Sie "define" in "undef" ändern.

#include <iostream>
#undef DEBUG  

int main() {    
#ifdef DEBUG
    std::cout << "WORKS!" << std::endl;
#endif
}

Möglicherweise können Sie mit Ihrem Compiler DEBUG außerhalb des Codes selbst definieren. An diesem Punkt können Sie den Code auf reduzieren

#include <iostream>

int main() {    
#ifdef DEBUG
    std::cout << "WORKS!" << std::endl;
#endif
}

Rufen Sie dann den Compiler mit einer Option wie -DDEBUG = 0 auf

Lesen Sie das Kapitel über defensive Programmierung in Steve McConnell, "Code Complete".

ManicDee
quelle