2014-12-27 4 views
44

Warum sind konstante Ausdrücke in GCC-Header-Dateien in Klammern eingeschlossen, so?So viele Klammern in GCC-Standard-Headern

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

Was wäre der Unterschied, wenn ich Klammern auf diese Weise weglassen würde?

#define INTMAX_MIN -9223372036854775807LL 
#define INTMAX_MAX 9223372036854775807LL 

Und warum gibt es das Suffix "L"? Wäre es das Gleiche, wenn ich folgendes schreibe?

#define INTMAX_MIN -9223372036854775807 
#define INTMAX_MAX 9223372036854775807 

Gibt es eine tatsächliche Nützlichkeit oder ist es immer die gleiche Sache?

Ich bin mir bewusst, dass das "L" lange steht und mir auch die Bedeutung von Klammern in C-Makros bewusst ist; Ich frage das um der Neugier willen.

Antwort

84

Wenn Sie

a = 7 INTMAX_MIN; 

schrieb würden Sie erwarten einen Syntaxfehler zu bekommen, weil Auf den ersten Blick wäre das ein illegaler Ausdruck. Und es wird, weil es erweitert

a = 7 (-9223372036854775807LL); 

die tatsächlich gibt Ihnen einen Syntaxfehler. Aber ohne die Klammern würde es erweitern, um:

a = 7 -9223372036854775807LL; 

das nicht einen Fehler nicht geben, obwohl sie offensichtlich nicht, was Sie wollten.

Allgemeiner gesagt, all diese Definitionen geben Erweiterungen für Dinge, die wie Identifikatoren aussehen. In einem arithmetischen Ausdruck ist ein Bezeichner ein "primärer Ausdruck", aber -9223372036854775807LL nicht. Ein eingeklammerter Ausdruck ist jedoch ein "primärer Ausdruck".

Und das ist der wahre Grund.So dass das Makro erweitert, was aussieht wie ein primärer Ausdruck für etwas, das ist ein primärer Ausdruck. Sie werden nie überrascht sein, was passiert. In der Programmierung ist Überraschung normalerweise schlecht.

Normalerweise ist es egal, aber die Leute, die die Definitionen geschrieben haben, wollen nicht, dass sie normalerweise funktionieren. Sie wollen, dass sie immer arbeiten.

Das abschließende LL kennzeichnet dieses Integer-Literal vom Typ long long, der typischerweise (und in diesem Fall) 64 Bit lang ist. Ohne das Suffix LL könnte das Literal als int, long int oder long long int interpretiert werden, je nachdem, welcher der erste 64-Bit-Werte unterstützt. Den Typ zu nageln kann genauso wichtig sein wie der Wert zu nageln.

+10

Sie könnten auch 'a = 7-INT_MAX; 'mit und ohne Klammern um' INT_MAX 'diskutieren, wobei Sie bemerken, dass das Ergebnis von' a = 7 - INT_MAX;' abweichen würde. –

+0

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

+3

@EricMSschmidt: _ ... blah, blah ... _ ** ... Es sei denn ... ** Oh drat! Der ursprüngliche Prozess des Präprozessors tendierte dazu, eine Antwort zu geben, aber die moderne (wie in 1989 oder später) Version tokenisiert die Eingabe und die Eingabe bleibt in Token, also '#define X -7' und' int main (void) {int x = 7-X; Rückgabe x; } 'ergibt ein Programm, das mit Status 14 beendet wird. Ich hätte mich erinnern sollen. –

19

Es ist eine gute Praxis Klammern auf einem Makro mit einem Integer-Konstante und ein unärer Operator wie folgt zu setzen:

#define BLA (-1) 

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

Als Neben PC-Lint vorschlagen parenthesizes in solchen Makros:

(Regel 973): parentheser #define N (-1) unärer Operator in Makro 'Symbol' nicht eingeklammerten - Ein unärer Es wurde gefunden, dass der Operator, der in einem ausdruckartigen Makro erscheint, nicht in Klammern gesetzt ist. Für Beispiel:

#define N -1 

Der Benutzer kann es vorziehen, solche Dinge zu klammern:

#define N (-1) 
13

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

Lassen Sie uns drei Makros kodieren, alle sind Dezimalkonstanten.

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

Obwohl MAXI hat keinen Suffix, dass es nicht int macht eingeben. MAXI hat den ersten Typ, in den es passt, entweder int, long, long long oder ein erweiterter Integer-Typ.

Obwohl MAXIL das L Suffix hat, wird es die erste Art hat sie paßt in entweder long, long long oder einen erweiterte Integer-Typ.

Obwohl MAXILL das LL Suffix hat, wird es die erste Art hat sie paßt in entweder long long oder ein erweiterte Integer-Typ.

In jedem Fall haben die Makros den gleichen Wert, aber potenziell verschiedene Typen.

Siehe C11dr §6.4.4.1 5 für die Typbestimmung.


Lasst uns versuchen, sie zu drucken und 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 korrekt sind, da alle drei Makros long long sind, die Vorhergehende haben Typ-Mis-Matches zwischen Formatbezeichner und der Nummer.

Wenn wir int haben, 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); 

Die maximale Breite Integer-Typ hat ein Format-Spezifizierer von "%" PRIdMAX. Dieses Makro kann nicht auf "%ld"und"%lld" erweitert werden, um MAXI, MAXIL, MAXILL aufzunehmen. Es ist auf "%lld" eingestellt, und Nummern, die sich auf intmax_t beziehen, müssen den gleichen Typ haben.In diesem Fall sollten long long und nur Formular MAXILL verwendet werden.


Andere Implementierungen können eine erweiterte Integer-Typ (wie int128_t) haben, wobei in diesem Fall eine Implementierung spezifischer Suffix oder irgendein Mechanismus verwendet werden könnte.

+0

Als Anmerkung, mit C11 '_Generic' (und vorher mit der populären' typeof' Erweiterung) sind Typen leichter beobachtbar geworden. (In C99 ohne Erweiterungen, ich Ich weiß nicht, wie der Unterschied zwischen "lang" und "lang lang" beobachtet werden kann, wenn sie die gleiche Größe und Darstellung haben; vorausgesetzt, dass es in Ordnung ist, wenn die Implementierung Annahmen über das Aufrufen von Konventionen macht, und es ziemlich unwahrscheinlich ist, dass "long" und "long long" unterschiedlich durchlaufen werden, bleibt die Frage, ob das Suffix wirklich für das strikte C99 benötigt wird.) – mafso

Verwandte Themen