Haben „true“ und „false“ ihre übliche Bedeutung in Präprozessor-Bedingungen?

Lesezeit: 5 Minuten

Benutzer-Avatar
Borph

Bei einem C++11-Compiler, der #error ist die richtige, mit der es enden sollte?

// no #includes!
#define SOMEMACRO true
#if SOMEMACRO
  #error "it was true"
#else
  #error "it was false"
#endif

Godbolt-Demo

Offensichtlich benutze ich #error nur so als test. Ich weiss true und false sind in der eigentlichen Sprache definiert, aber dies ist ein Präprozessorkontext. In C99 scheint es vom Präprozessor nicht erkannt zu werden.

Ich frage, weil es scheint, dass alle Compiler, die ich ausprobiert habe, es als “wahr” ansehen, während ein statisches Codeanalysetool darauf besteht true ist nicht definiert, implizit falsch und endet in “es war falsch”.

  • C++: Ja, das sind Schlüsselwörter; C: nein sind sie nicht (stdbool.h).

    – iBug

    8. Februar 2021 um 8:31 Uhr


In allen ISO-C++-Standards beides true und false sind Schlüsselwortkonstanten, genau wie nullptr in C++11. So #if SOMEMACRO = #if true und der Präprozessor geht zum Wahrheitszweig.

In C jedoch auch nicht true Noch false ist schon mal ein Stichwort. Sie sind Makros definiert 1 und 0 bzw. ab C99 und mit #include <stdbool.h>. Dies tut bedeutet das aber, wenn man es nicht einschließt stdbool.hsollte sich der Compiler über nicht erkannte Bezeichner beschweren true, false usw. Nach dem Einfügen des Headers #if SOMEMACRO ist jetzt #if 1was Wahrheit in C ist.

Zur Vorverarbeitung dieses Zitats aus CppReferenz ist aussagekräftig:

Jeder Bezeichner, der nicht wörtlich ist, nicht definiert mit #define Richtlinie, wertet zu 0.

In Ihrem (wahrscheinlich C-orientierten) statischen Analysetool sieht es also aus true als Nicht-#define-definierter Bezeichner und wertet daher aus true bis Null. Sie werden dieses Verhalten nicht beobachten, wenn Sie ein C++-Analysetool verwenden.

In diesem Fall hätten Sie das wahrscheinlich nicht verpassen sollen #include <stdbool.h> in erster linie aber.

  • Als Referenz, true und false sind speziell herausgegriffen nicht ersetzt werden, wenn andere Identifikatoren ersetzt werden. nullptr ist ein Literal, aber es bekommt diese Behandlung nicht, was Sie mit einer Bedingung wie sehen können #if nullptr + 2 == 2 das würde nicht kompilieren, wenn nullptr wurden nicht durch ersetzt 0.

    – Chris

    8. Februar 2021 um 8:47 Uhr


  • @chris, ich habe es gelesen, aber es gibt keine Erklärung für das Warum. Hast du eine Erklärung?

    – Paul Ogilvie

    8. Februar 2021 um 10:26 Uhr

  • @PaulOgilvie, ich kann nur spekulieren, aber true und false ersetzt werden durch 1 und 0 würde dazu führen, dass die Literale ihren booleschen Typ verlieren, wenn der Präprozessor fertig ist und die eigentliche Sprache übernimmt.

    – Chris

    8. Februar 2021 um 10:28 Uhr

  • @chris, aber in C, wenn stdbool.h enthalten ist, dann wahr und falsch sind #defned und haben keine boolesche Bedeutung. Nur in C++ haben sie das, aber dann sollten sie nicht in stdbool definiert werden. Wird für C und C++ derselbe Präprozessor verwendet?

    – Paul Ogilvie

    8. Februar 2021 um 10:33 Uhr

  • @PaulOgilvie, Soweit mir bekannt ist, ist der Präprozessor bis auf sehr geringfügige Unterschiede wie diesen identisch (z. B. habe ich Boost.PP in C arbeiten lassen). Der C-Präprozessor existierte schon vorher _Bool Es macht also Sinn, dass es dort keinen Sonderfall gibt (selbst heute, wo die Definitionen 1 und 0 sind), aber es scheint, dass es in diesem speziellen Fall kaum Nachteile hatte, Typinformationen in C++ beizubehalten, als dies der Fall war bool und solche typisierten Literale von Anfang an. Und das ist richtig, in C++ liefert stdbool.h keine #defines für bool, trueund false da sie Teil der eigentlichen Sprache sind.

    – Chris

    8. Februar 2021 um 10:48 Uhr


Benutzer-Avatar
Benutzer3840170

Entsprechend [cpp.cond]/4 Zoll dem C++11-Standard:

Vor der Auswertung werden Makroaufrufe in der Liste der Vorverarbeitungstoken, die zum steuernden konstanten Ausdruck werden, ersetzt (mit Ausnahme der Makronamen, die durch die defined unärer Operator), genau wie im normalen Text. […] Nach allen Ersetzungen aufgrund der Makroerweiterung und der defined unärer Operator ausgeführt wurden, alle verbleibenden Bezeichner und Schlüsselwörter, ausser für true und falsewerden durch die pp-Nummer ersetzt 0, und dann wird jedes Vorverarbeitungstoken in ein Token konvertiert. Die resultierenden Token umfassen den steuernden konstanten Ausdruck, der ist bewertet nach den Regeln der [expr.const] Verwenden von Arithmetik, die mindestens die Bereiche hat, die in angegeben sind [support.limits]. […] Jeder Teilausdruck mit Typ bool wird einer integralen Heraufstufung unterzogen, bevor die Verarbeitung fortgesetzt wird.

Betonung von mir; aus den fettgedruckten Stellen folgt das bool-typisierte Ausdrücke sollen in Präprozessorbedingungen genau wie in der eigentlichen Sprache unterstützt werden, einschließlich bool Literale true und false. Das [expr.const] Auf den Abschnitt, der konstante Ausdrücke definiert, wird in anderen Abschnitten verwiesen, die ihn im Nicht-Vorverarbeitungskontext verwenden, woraus folgt, dass die Auswertungsregeln im Präprozessor und in der eigentlichen Sprache gleich sind.

Ich würde davon ausgehen, dass eine ähnliche Sprache in allen weiteren Revisionen des C++-Standards und wahrscheinlich auch in früheren Versionen vorkommt. In C hingegen true und false sind keine Schlüsselwörter, sondern in definierte Makros stdbool.hsodass der Präprozessor sie wie jedes andere Token behandelt.

Die übliche Praxis ist zu verwenden 1 und 0 für logische Werte in Präprozessorausdrücken für maximale Portabilität und vorzugsweise um zu vermeiden, dass vollständig direkt auf sie verwiesen wird.

Wie andere Antworten bereits richtig darauf hingewiesen haben, true und false sollte dort mit C++-Compilern funktionieren.

OP hier: Es war tatsächlich ein Konfigurationsproblem des SCA-Tools. In Helix die Option -preproccppkeywords, die besagt: „Wenn aktiviert, werden die alternativen C++-Token als Schlüsselwörter behandelt.“ war dafür verantwortlich. Beim Einschalten verhält es sich wie erwartet. true und false werden während der Vorverarbeitung erkannt.

1059340cookie-checkHaben „true“ und „false“ ihre übliche Bedeutung in Präprozessor-Bedingungen?

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

Privacy policy