Warum (und wann) muss ich nach sizeof Klammern verwenden?

80

Folgendes kann nicht kompiliert werden:

typedef int arr[10];
int main(void) {
    return sizeof arr;
}

sizeof.c:3: error: expected expression before ‘arr’

aber wenn ich es ändere

sizeof(arr);

alles ist gut. Warum?

Blauverschiebung
quelle
sizeof als Operator ist in ansi-c nicht verfügbar
Grim
2
@Kostya: Meine Kopie von K & R (die früheste Beschreibung der C-Sprache, die ich habe) ist sehr weit entfernt und ich kann sie jetzt nicht überprüfen, aber ich bin zu 110% sicher, dass sie im sizeofWesentlichen genauso beschreibt wie C99 Standard heute. sizeofist verfügbar, bevor C 1989 von ANSI standardisiert wurde.
pmg

Antworten:

119

Gemäß 6.5.3 gibt es zwei Formen für sizeofFolgendes:

sizeof unary-expression
sizeof ( type-name )

Da arrIhr Code a ist type-name, muss er in Klammern gesetzt werden.

Ise Glyzinien
quelle
15
+1 und, um das zu verstärken, sizeofein Operator: Die Klammern "gehören" zum Typ, nicht zum Operator.
PMG
@pmg: Danke für die Klarstellung! Ja, wie Sie bereits erwähnt haben, bezeichnet der Standard sizeofeinen Operator.
Ise Wisteria
4
@pmg: Ich glaube nicht, dass klar ist, wozu die Klammern "gehören". Die Syntax der zweiten Form besteht aus drei Token und einem nicht-terminalen : sizeof ( type-name ). Aber für die erste Form, Sie können schreiben, zum Beispiel sizeof(x), und obwohl es wie ein Funktionsaufruf aussieht (wenn sizeofwar kein Schlüsselwort), es ist wirklich ein Bediener auf einen geklammerten Ausdruck angewandt. Hast du das gedacht?
Keith Thompson
3
Was ich meine ist, dass sizeofes syntaktisch ist, sizeof <SOMETHING>im Gegensatz zu Funktionen, zum Beispiel zu einem, printfwas ist printf ( <SOMETHING> ). Die Klammern gehören zu, printfaber nicht zu sizeof. Wenn sizeofes auf einen Typnamen in Klammern angewendet wird, stelle ich mir das gerne als eine Besetzung von nichts vor - "nur" den Typ "zurückgeben".
PMG
2
@pmg: Sie können es sicherlich so sehen, aber ich finde es irreführend. Die einzige wirkliche Ähnlichkeit mit einer Besetzung besteht darin, dass sie einen Typnamen in Klammern hat, und das ist nur ein Zufall der syntaktischen Bequemlichkeit. Ich stelle es mir lieber sizeof ( type-name )als einen eigenen Ausdruck vor. (Der Standard nennt es einen Operator, ist aber ( type-name )nicht wirklich ein Operand im üblichen Sinne.)
Keith Thompson
43

Auf diese Weise wird die Sprache angegeben. Typnamen müssen hier in Klammern gesetzt werden.

Angenommen, die Grammatik sieht folgendermaßen aus:

sizeof unary-expression sizeof type-name

Nun wäre zB der folgende Ausdruck mehrdeutig:

sizeof int * + 0

Es könnte entweder sizeof(int *) + 0oder sein sizeof(int) * +0. Diese Mehrdeutigkeit tritt bei unären Ausdrücken nicht auf, da ein an einen Ausdruck angehängtes Sternchen kein Ausdruck ist (bei einigen Typnamen ist das Anhängen eines wieder ein Typname).

Hier musste etwas angegeben werden, und die Notwendigkeit, Typnamen in Klammern zu setzen, ist eine Möglichkeit, die Mehrdeutigkeit zu lösen.

Mafso
quelle
-3

Ich denke, das liegt daran, dass du es hast typedef. Wenn Sie es entfernen, sollte es kompiliert werden.

Beispiel aus Wikipedia:

/* the following code fragment illustrates the use of sizeof     
 * with variables and expressions (no parentheses needed),
 * and with type names (parentheses needed)    
 */
char c;
printf("%zu,%zu\n", sizeof c, sizeof (int));
baz
quelle