So viele Klammern in gcc-Standard-Headern

Lesezeit: 6 Minuten

Warum sind konstante Ausdrücke in GCC-Header-Dateien wie hier in Klammern eingeschlossen?

#define INTMAX_MIN (-9223372036854775807LL)
#define INTMAX_MAX (9223372036854775807LL)

Was wäre der Unterschied, wenn ich auf diese Weise Klammern weglasse?

#define INTMAX_MIN -9223372036854775807LL
#define INTMAX_MAX 9223372036854775807LL

Und warum gibt es das Suffix „L“? Wäre es genauso, wenn ich folgendes schreibe?

#define INTMAX_MIN -9223372036854775807
#define INTMAX_MAX 9223372036854775807

Gibt es einen tatsächlichen Nutzen oder ist es immer dasselbe?

Ich bin mir bewusst, dass das ‘L’ für lang steht, und ich bin mir auch der Bedeutung von Klammern in C-Makros bewusst; Ich frage das aus reiner Neugier.

Benutzeravatar von ganbustein
Ganbüstein

Wenn du geschrieben hast

a = 7 INTMAX_MIN;

Sie würden einen Syntaxfehler erwarten, da dies auf den ersten Blick ein illegaler Ausdruck wäre. Und das wird es, denn es dehnt sich aus

a = 7 (-9223372036854775807LL);

was Ihnen tatsächlich einen Syntaxfehler gibt. Aber ohne die Klammern würde es sich erweitern zu:

a = 7 -9223372036854775807LL;

was Ihnen keinen Fehler gibt, obwohl es offensichtlich nicht das ist, was Sie beabsichtigt haben.

Allgemeiner ausgedrückt, alle diese Definitionen geben Erweiterungen für Dinge, die wie Bezeichner aussehen. In einem arithmetischen Ausdruck ist ein Bezeichner ein “primärer Ausdruck”, -9223372036854775807LL jedoch nicht. Ein eingeklammerter Ausdruck ist jedoch ein “primärer Ausdruck”.

Und das ist der wahre Grund. Damit erweitert sich das Makro was sieht aus wie ein primärer Ausdruck für etwas, das ist ein primärer Ausdruck. Sie werden nie überrascht sein, was passiert. Beim Programmieren ist Überraschung normalerweise schlecht.

Normalerweise spielt es keine Rolle, aber die Leute, die die Definitionen geschrieben haben, wollen nicht, dass sie normalerweise funktionieren. Sie wollen, dass sie immer funktionieren.

Das abschließende LL markiert dieses Integer-Literal als Typ long long, was typischerweise (und in diesem Fall) 64 Bit ist. Ohne das Suffix LL könnte das Literal als int, long int oder long long int interpretiert werden, je nachdem, was zuerst 64-Bit-Werte unterstützt. Das Festhalten des Typs kann genauso wichtig sein wie das Festhalten des Werts.

  • Sie könnten auch diskutieren a = 7-INT_MAX; mit und ohne Klammern um INT_MAXwobei darauf hingewiesen wird, dass das Ergebnis anders wäre als a = 7 - INT_MAX;.

    – Jonathan Leffler

    27. Dezember 2014 um 2:41 Uhr

  • @JonathanLeffler Wie würde das Ergebnis anders aussehen? Sie sollten keine Klammern für benötigen INT_MAX da ein Integer-Literal ein primärer Ausdruck ist.

    – Eric M. Schmidt

    27. Dezember 2014 um 5:11 Uhr


  • @EricMSchmidt: … bla, bla… …Wenn nicht… Ach verdammt! Der ursprüngliche separate Präprozessorprozess gab tendenziell eine Antwort, aber die moderne (wie 1989 oder später) Version tokenisiert die Eingabe und die Eingabe bleibt tokenisiert, also #define X -7 und int main(void) { int x = 7-X; return x; } ergibt ein Programm, das mit Status 14 beendet wird. Ich hätte mich erinnern sollen.

    – Jonathan Leffler

    27. Dezember 2014 um 5:27 Uhr


  • “Das Literal würde als gewöhnliche ganze Zahl interpretiert werden” ist in @mafso-Kommentaren falsch. Versuchen printf("%zu\n", sizeof (9223372036854775807));

    – chux – Wiedereinsetzung von Monica

    27. Dezember 2014 um 6:38 Uhr

  • @mafso: Das ist sprachlich nicht ganz richtig. Die einzige Standardversion der C-Sprache, die die Verwendung erlaubte ohne Vorzeichen Typen für Konstanten ohne Suffix war C89/90. Diese Funktionalität wurde in C99 verboten. Suffixlose Konstanten können nur haben unterzeichnet Typen. Wenn die Konstante nicht in den größten vorzeichenbehafteten Typ passt, ist das Verhalten undefiniert. Dh die Sprache unterstützt die Verwendung nicht unsigned long long für eine Konstante ohne Suffix.

    – AnT steht zu Russland

    27. Dezember 2014 um 7:32 Uhr


Benutzeravatar von ouah
ouah

Es empfiehlt sich, ein Makro mit einer Ganzzahlkonstanten und einem unären Operator wie folgt in Klammern zu setzen:

#define BLA (-1)

als unäre Operatoren (- hier) haben in C nicht die höchste Priorität. Postfix-Operatoren haben eine höhere Priorität als unäre Operatoren. Denken Sie daran, dass C zum Beispiel keine negativen Konstanten hat -1 ist ein konstanter Ausdruck, dem das vorangestellt ist - unärer Operator.

Nebenbei schlägt PC-Lint Klammern in solchen Makros vor:

(Regel 973): Klammer #define N (-1) Unärer Operator in Makro ‘Symbol’ nicht eingeklammert — Es wurde festgestellt, dass ein unärer Operator, der in einem ausdrucksähnlichen Makro erscheint, nicht eingeklammert ist. Zum Beispiel:

#define N -1

Der Benutzer kann es vorziehen, solche Dinge einzuklammern wie:

#define N (-1)

chux – Stellt Monicas Benutzeravatar wieder her
Chux – Wiedereinsetzung von Monica

Diese Antwort versucht zu zeigen, warum die LL wird gebraucht. (Es ist nicht einfach.)
Andere Antworten haben gezeigt, warum Klammern benötigt werden.

Lassen Sie uns drei Makros programmieren, alle sind es Dezimalkonstanten.

#define MAXILL (9223372036854775807LL)
#define MAXIL  (9223372036854775807L)
#define MAXI   (9223372036854775807)

Wenngleich MAXI hat kein Suffix, das macht es nicht zum Typ int. MAXI wird entweder den ersten Typ haben, in den es passt int, long, long long oder ein erweiterter ganzzahliger Typ.

Wenngleich MAXIL hat die L Suffix hat es auch den ersten Typ, in den es passt long, long long oder ein erweiterter ganzzahliger Typ.

Wenngleich MAXILL hat die LL Suffix hat es auch den ersten Typ, in den es passt long long oder ein erweiterter ganzzahliger Typ.

Die Makros haben in jedem Fall den gleichen Wert, aber möglicherweise verschiedene Typen.

Siehe C11dr §6.4.4.1 5 zur Typbestimmung.


Lassen Sie uns versuchen, sie zu drucken und zu haben int und long sind 32-bit und long long und intmax_t sind 64.

printf("I   %d %d %d",       MAXI, MAXIL, MAXILL);    //Error: type mismatch
printf("LI  %ld %ld %ld",    MAXI, MAXIL, MAXILL);    //Error: type mismatch
printf("LLI %lld %lld %lld", MAXI, MAXIL, MAXILL);    //Ok

Alle drei in der letzten Zeile sind korrekt, wie alle drei Makros long longweisen die vorangehenden Typkonflikte zwischen dem Formatbezeichner und der Zahl auf.

Wenn wir haben int ist 32-bit und long, long long und intmax_t 64 sind, dann sind die folgenden richtig.

printf("LI  %ld %ld",    MAXI, MAXIL);
printf("LLI %lld", MAXILL);

Der ganzzahlige Typ mit maximaler Breite hat einen Formatbezeichner von "%" PRIdMAX. Dieses Makro kann nicht erweitert werden "%ld" und "%lld" unterzubringen MAXI, MAXIL, MAXILL. Es ist eingestellt "%lld" und Zahlen im Zusammenhang mit intmax_t müssen den gleichen Typ haben. In diesem Fall, long long und nur bilden MAXILL sollte benutzt werden.


Andere Implementierungen könnten einen erweiterten Integer-Typ haben (wie z int128_t), in welchem ​​Fall ein implementierungsspezifisches Suffix oder irgendein Mechanismus verwendet werden könnte.

  • Als Anmerkung, mit C11 _Generic (und davor mit dem populären typeof Erweiterung) Typen sind leichter beobachtbar geworden. (In C99 ohne Erweiterungen weiß ich nicht, wie der Unterschied zwischen long und long long beobachtet werden könnten, wenn sie die gleiche Größe und Darstellung haben; vorausgesetzt, dass es in Ordnung ist, wenn die Implementierung Annahmen über Aufrufkonventionen macht, und dass dies ziemlich unwahrscheinlich ist long und long long anders übergeben werden, bleibt die Frage, ob das Suffix wirklich für strenges C99 benötigt wird.)

    – Mafso

    27. Dezember 2014 um 8:11 Uhr

1404130cookie-checkSo viele Klammern in gcc-Standard-Headern

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

Privacy policy