Warum wird dieser Code kompiliert?
_Static uint32_t my_arr[2];
_Static_assert(sizeof(my_arr) == 8, "");
_Static_assert(sizeof(my_arr[0]) == 4, "");
_Static_assert(sizeof(my_arr)[0] == 4, "");
Die ersten beiden Behauptungen sind offensichtlich korrekt, aber ich hätte erwartet, dass die letzte Zeile fehlschlägt, da ich verstehe, dass dies sizeof()
zu einem ganzzahligen Literal ausgewertet werden sollte, das nicht als Array behandelt werden kann. Mit anderen Worten, es würde genauso fehlschlagen wie die folgende Zeile:
_Static_assert(4[0] == 4, "");
Interessanterweise kann das Folgende tatsächlich nicht kompiliert werden (was sollte dasselbe tun, nein?):
_Static_assert(*sizeof(my_arr) == 4, "");
Fehler: ungültiges Typargument von unary '*' (habe 'long unsigned int') _Static_assert (* sizeof (my_arr) == 4, "");
Wenn es darauf ankommt, verwende ich gcc 5.3.0
( sizeof( my_arr ) )[ 0 ]
scheitert.Antworten:
sizeof
ist keine Funktion. Es ist ein unärer Operator wie!
oder~
.sizeof(my_arr)[0]
analysiert alssizeof (my_arr)[0]
, was nursizeof my_arr[0]
mit redundanten Klammern ist.Dies ist genau wie das
!(my_arr)[0]
Parsen als!(my_arr[0])
.Im Allgemeinen haben Postfix-Operatoren eine höhere Priorität als Präfix-Operatoren in C.
sizeof *a[i]++
parses assizeof (*((a[i])++))
(die Postfix-Operatoren[]
und++
werden zuerst angewendeta
, dann die Präfix-Operatoren*
undsizeof
).(Dies ist die Ausdrucksversion von
sizeof
. Es gibt auch eine Typversion, die einen Typnamen in Klammern verwendet:sizeof (TYPE)
In diesem Fall wären die Parens erforderlich und Teil dersizeof
Syntax.)quelle
sizeof
, ein unärer Operator zu sein."... parses as sizeof (my_arr[0])"
? Das Hinzufügen eines Leerzeichens ändert nichts.sizeof((my_array)[0])
stattdessen empfehlensizeof
hat zwei "Versionen":sizeof(type name)
undsizeof expression
. Ersteres erfordert ein Paar()
um seine Argumentation. Aber der letztere - derjenige mit einem Ausdruck als Argument - hat kein()
Argument. Was auch immer()
Sie im Argument verwenden, wird als Teil des Argumentausdrucks und nicht als Teil dersizeof
Syntax selbst angesehen.Da
my_arr
der Compiler als Objektname und nicht als Typname bekannt ist, wird Ihrsizeof(my_arr)[0]
Compiler vom Compiler tatsächlich alssizeof
auf einen Ausdruck angewendet angesehen :sizeof (my_arr)[0]
, wobei(my_arr)[0]
der Argumentausdruck ist. Die()
Umgebung des Array-Namens ist rein überflüssig. Der gesamte Ausdruck wird interpretiert alssizeof my_arr[0]
. Dies entspricht Ihrem vorherigensizeof(my_arr[0])
.(Dies bedeutet übrigens, dass Ihr Vorgänger
sizeof(my_arr[0])
auch ein Paar überflüssiger enthält()
.)Es ist ein weit verbreitetes Missverständnis, dass
sizeof
die Syntax irgendwie ein Paar von()
Argumenten erfordert . Dieses Missverständnis führt die Intuition der Menschen in die Irre, wenn sie solche Ausdrücke wie interpretiertsizeof(my_arr)[0]
.quelle
int
jedoch kein gültiger Ausdruck, sodass Sie den nicht verwenden können zweite Form damit.[]
haben eine höhere Priorität alssizeof
. Sosizeof(my_arr)[0]
ist das gleiche wiesizeof((my_arr)[0])
.Hier ist ein Link zu einer Prioritätstabelle.
quelle
Sie verwenden die Version des
sizeof
Operators, der einen Ausdruck als Parameter verwendet. Anders als bei einem Typ sind keine Klammern erforderlich. Daher ist der Operand einfach(my_arr)[0]
, wobei die Klammern redundant sind.quelle