Gibt es einen logischen Kurzschluss im C-Präprozessor?

Lesezeit: 6 Minuten

Benutzer-Avatar
kein Benutzer

Das gcc-Dokumentation für cpp über die erklären #if Richtlinie:

[…] und logische Operationen (&& und ||). Die beiden letzteren gehorchen den üblichen Kurzschlussregeln des Standards C.

Was bedeutet das? Es gibt keine Auswertung von Ausdrücken während der Vorverarbeitung, wie kann es also kurzgeschlossen werden?

  • Ich denke, Kurzschluss bedeutet hier, den zweiten Term nicht auszuwerten, wenn die Auswertung des ersten Terms den resultierenden Wert vollständig bestimmt

    – jean-loup

    4. Juni 2014 um 12:38 Uhr

  • Aber wie kann man das sagen? Warum sollte das wichtig sein?

    – Aschepler

    4. Juni 2014 um 12:39 Uhr

  • Interessante Frage.

    – Leichtigkeitsrennen im Orbit

    4. Juni 2014 um 12:43 Uhr


  • In Standard-C, #if will nur einen konstanten Ausdruck. Wenn dieser konstante Ausdruck ist my_const1 && my_const2 dann wird der Ausdruck so ausgewertet, wie er an anderer Stelle im Code gewesen wäre, so einfach ist das. Aber ich bin mir sicher, dass GCC viele seltsame, überflüssige Erweiterungen für den Präprozessor hat, also scheint der Kommentar für sie zu gelten.

    – Ludin

    4. Juni 2014 um 13:26 Uhr

  • Woher wissen Sie, dass hier keine Auswertung von Ausdrücken während der Vorverarbeitung erfolgt?

    – Hacken

    4. Juni 2014 um 14:29 Uhr

Benutzer-Avatar
jthill

Ganz einfach: Undefinierte Makros haben den numerischen Wert Null, und die Division durch Null ist illegal.

#if FIXEDSIZE && CHUNKSIZE/FIXEDSIZE > 42
#define USE_CELLPOOL
#endif

#if wertet den Rest seiner Zeile als ganzzahligen konstanten Ausdruck aus. Ihre verlinkte Dokumentation beginnt:

Mit der ‘#if’-Direktive können Sie den Wert eines arithmetischen Ausdrucks testen, anstatt nur die Existenz eines Makros.

Das ist keine gcc-Erweiterung, die Standard-Syntax für #if ist

#ifconstant-expression new-line groupopt.

Der C99-Präprozessor behandelt alle Konstanten als [u]intmax_t.

  • Denn wenn Sie das nicht haben FIXEDSIZE test erhalten Sie “Fehler: Division durch Null in #if”. Ich wollte gerade eine sehr ähnliche Antwort posten.

    – AShelly

    4. Juni 2014 um 14:45 Uhr


  • @hackks Aber ist es in diesem Beispiel nicht trivial zu erkennen, dass der Präprozessor die Division auswertet?

    – Wertigkeit

    4. Juni 2014 um 14:49 Uhr

  • @MM.; Hmm. Darum geht es in der Frage: Es gibt keine Auswertung von Ausdrücken während der Vorverarbeitung, wie kann es also kurzgeschlossen werden?

    – Hacken

    4. Juni 2014 um 14:51 Uhr

  • @hackks Ich sehe es jetzt, du hast Recht. Das Ausfüllen des momentanen blinden Flecks aller anderen beantwortet die Frage von OP nicht direkt. Festsetzung.

    – jthill

    4. Juni 2014 um 14:52 Uhr


  • @Tempel -Wundefwie in der Antwort von Jeffrey Thomas erwähnt, obwohl ich das nicht als a bezeichnen würde Nebeneffekt exakt. Aber das ist es. Keiner der Operatoren wird unterstützt in #if haben nebenwirkungen und bezeichner auf einer #if Zeile, die weder Makros noch die winzige Handvoll Schlüsselwörter sind, in denen sie gültig sind #if (nur in C99 defined; in C++ auch Dinge wie and, bitand, trueund false; C2011 könnte auch noch etwas hinzufügen, weiß ich nicht mehr) werden einheitlich durch die Konstante ersetzt 0egal welche Bedeutung sie außerhalb haben #if.

    – zol

    4. Juni 2014 um 18:41 Uhr

Benutzer-Avatar
Jeffrey Thomas

Worauf sie sich beziehen, ist && und || Betreiber für #if

#if defined (AAA) || defined (BBB)

Wenn defined (AAA) ist dann definiert defined (BBB) wird nie ausgewertet.


AKTUALISIEREN

Das Ausführen der Berechnung wird also kurzgeschlossen. Zum Beispiel, wenn Sie mit bauen -Wundef um vor der Verwendung von undefinierten Makros zu warnen.

#if defined FOO && FOO > 1000
#endif

#if FOO > 1000
#endif

wird darin enden, dass

thomas:~ jeffery$ gcc foo.c -Wundef
foo.c:4:5: warning: 'FOO' is not defined, evaluates to 0 [-Wundef]
#if FOO > 1000
    ^
1 warning generated.

Die erste Version generiert also nicht die undefinierte Makrowarnung, weil FOO > 1000 wird nicht ausgewertet.


ALTE SÜSSE

Dies wird wichtig, wenn der zweite Teil ein Makro ist, das Nebenwirkungen hat. Das Makro würde nicht ausgewertet, daher würden die Seiteneffekte nicht stattfinden.


Um Makromissbrauch zu vermeiden, gebe ich ein einigermaßen vernünftiges Beispiel

#define FOO
#define IF_WARN(x) _Pragma (#x) 1
#if defined(FOO) || IF_WARN(GCC warning "FOO not defined")
#endif

Nachdem ich dieses Beispiel erstellt habe, stoße ich nun auf ein Problem. IF_WARN wird immer ausgewertet.

huh, mehr Forschung erforderlich.


Tja foo… jetzt wo ich es nochmal gelesen habe.

Makros. Alle Makros im Ausdruck werden erweitert, bevor die eigentliche Berechnung des Werts des Ausdrucks beginnt.

  • Was ändert es, da der Präprozessor keine Nebenwirkungen hat? Edit: Scheint mich zu irren, also würde ich gerne ein Beispiel sehen 🙂

    – QUentin

    4. Juni 2014 um 12:39 Uhr


  • Makros können Nebenwirkungen haben.

    – Jeffrey Thomas

    4. Juni 2014 um 12:40 Uhr

  • @JefferyThomas: Wie zum Beispiel?

    – Leichtigkeitsrennen im Orbit

    4. Juni 2014 um 12:42 Uhr

  • Wenn du #define BBB {volatile int x=0;} dann enthält das Makro einen Nebeneffekt, aber dieser Nebeneffekt ist nur relevant, wenn das Makro vom Programm aufgerufen wird, nicht während der Vorprozessorauswertung. Mischen Sie diese Dinge nicht.

    – Ludin

    4. Juni 2014 um 13:17 Uhr

  • @RudyVelthuis: Der ganze Sinn der Frage besteht darin, zu fragen, ob es wichtig ist, ob ein Ausdruck ausgewertet wird und der andere nicht. Diese Antwort lehrt nur, was Kurzschließen ist, ohne sogar versuchen um die Frage zu beantworten. Was Ihren letzten Kommentar betrifft, so sind “Präprozessorausdruck” und “C++-Ausdruck” zwei sehr unterschiedliche Dinge, und ich denke, es ist ziemlich klar, auf welchen sich das OP bezog.

    – Leichtigkeitsrennen im Orbit

    4. Juni 2014 um 13:22 Uhr


Benutzer-Avatar
hackt

Es gibt keine Auswertung von Ausdrücken während der Vorverarbeitung, wie kann es also kurzgeschlossen werden?

Ja, der Ausdruck wird während der Vorverarbeitung ausgewertet.

C11: 6.10.1 Bedingte Einbeziehung (p4):

Vor der AuswertungMakroaufrufe in der Liste der Vorverarbeitungstoken, die zu …

In einer Fußnote 166:

Weil die Die Steuerung des konstanten Ausdrucks wird während der Übersetzungsphase 4 ausgewertetalle Kennungen….

Diese Aussagen belegen dies eindeutig Es gibt eine Auswertung des Ausdrucks in der Vorverarbeitung. Die notwendige Bedingung ist, dass der steuernde Ausdruck einen ganzzahligen Wert ergeben muss.
Jetzt der Betreiber && und || befolgen die üblichen Kurzschlussregeln der Norm C, wie in angegeben GNU-Dokument.

Führen Sie nun dieses Programm mit und ohne aus // und sehen Sie sich das Ergebnis an, um das Kurzschlussverhalten zu sehen:

#include<stdio.h>
#define macro1 1
//#define macro2 1
int main( void )
{
    #if  defined (macro1)  && defined (macro2)
    printf( "Hello!\n" );
    #endif
    printf("World\n"); 
    return 0;
}

  • ein einfaches Beispiel für erweiterte Makros in #if Ausdrücke: #define VERSION 5.0 ... #if VERSION > 6.0 && defined (cplusplus). Dies überprüft nicht, ob cplusplus überhaupt definiert ist, da die MIN_VERSION sowieso zu niedrig ist. Und das Makro wird definitiv erweitert in 5.0.

    – Rudy Velthuis

    4. Juni 2014 um 13:56 Uhr

  • @RudyVelthuis; Ich stimmte zu. Aber was OP eigentlich nach der Auswertung des Ausdrucks fragt, nicht nach dem Kurzschlussverhalten. (Übrigens habe ich Ihre Antwort nicht abgelehnt, im Allgemeinen wurde ich davon abgehalten, Antworten auf eine so typische Frage abzulehnen).

    – Hacken

    4. Juni 2014 um 14:03 Uhr


  • Ich hatte keine Antwort, nur ein paar Kommentare, also gibt es nichts abzulehnen.

    – Rudy Velthuis

    4. Juni 2014 um 14:11 Uhr

  • @RudyVelthuis; Ups, ich dachte, Sie wären Jeffery Thomas 😛

    – Hacken

    4. Juni 2014 um 14:21 Uhr

Benutzer-Avatar
masud

Das Auswerten von Makrobedingungen ist ein Teil (ein Hauptteil) der Vorverarbeitung, daher tritt es auf und das Kurzschließen ist dort sinnvoll. Sie können Beispiele für die anderen Antworten sehen.

EIN bedingt ist eine Direktive, die die anweist Präprozessor um auszuwählen, ob ein Stück Code in den endgültigen Token-Stream aufgenommen werden soll, der an den Compiler übergeben wird. Präprozessor-Bedingungen kann arithmetische Ausdrücke testen oder ob ein Name als Makro definiert ist oder beides gleichzeitig mit dem speziellen definierten Operator.

Außerdem es kann Kompilierzeit reduzieren. Das Verändern der folgenden Auswertungen kann die Kompilierung beschleunigen (abhängig von der Implementierung eines Compilers).

1371380cookie-checkGibt es einen logischen Kurzschluss im C-Präprozessor?

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

Privacy policy