¿Por qué sizeof (my_arr) [0] compila e igual sizeof (my_arr [0])?


129

¿Por qué se compila este código?

_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, "");

Las primeras 2 afirmaciones son obviamente correctas, pero hubiera esperado que la última línea fallara, ya que entiendo que sizeof()debería evaluar un literal entero, que no puede tratarse como una matriz. En otras palabras, fallaría de la misma manera que falla la siguiente línea:

_Static_assert(4[0] == 4, "");

Curiosamente, lo siguiente no puede compilarse (que debería estar haciendo lo mismo, ¿no?):

_Static_assert(*sizeof(my_arr) == 4, "");

error: argumento de tipo no válido de '*' unario (tiene 'int largo sin signo') _Static_assert (* sizeof (my_arr) == 4, "");

Si importa, estoy usando gcc 5.3.0


15
Sospecho que ( sizeof( my_arr ) )[ 0 ]falla.
Andrew Henle

Un duplicado reciente tiene otra variación en esta sorpresa de sintaxis: ¿Por qué compila sizeof (x) ++?
Peter Cordes

Respuestas:


197

sizeofNo es una función. Es un operador unario como !o ~.

sizeof(my_arr)[0]analiza como sizeof (my_arr)[0], que es solo sizeof my_arr[0]con paréntesis redundantes.

Esto es como !(my_arr)[0]analiza como !(my_arr[0]).

En general, los operadores de postfix tienen mayor prioridad que los operadores de prefijo en C. sizeof *a[i]++analiza como sizeof (*((a[i])++))(los operadores de postfix []y ++se aplican aprimero, luego los operadores de prefijo *y sizeof).

(Esta es la versión de expresión de sizeof. También hay una versión de tipo, que toma un nombre de tipo entre paréntesis:. sizeof (TYPE)En ese caso, se requerirían los parens y parte de la sizeofsintaxis).


14
Definitivamente sabía que sizeof era un operador unario y no una función, pero lo olvidé por completo. Woops Gracias por la explicación detallada. El hecho de que [] tiene mayor precedencia que * es interesante independientemente.
bgomberg

@melpomene Interesante. Nunca he pensado en sizeofser un operador unario.
mutantkeyboard

55
No quiere decir "... parses as sizeof (my_arr[0])"? Solo agregar un espacio realmente no cambia nada.
Bernhard Barker

En su sizeof((my_array)[0])lugar, recomendaría
bolov


46

sizeoftiene dos "versiones": sizeof(type name)y sizeof expression. El primero requiere un par de ()argumentos. Pero este último, el que tiene una expresión como argumento, no tiene ()alrededor de su argumento. Cualquier cosa ()que use en el argumento se considera parte de la expresión del argumento, no parte de la sizeofsintaxis en sí.

Como my_arrel compilador lo conoce como un nombre de objeto, no como un nombre de tipo, sizeof(my_arr)[0]el compilador lo ve realmente como sizeofaplicado a una expresión: sizeof (my_arr)[0]donde (my_arr)[0]está la expresión de argumento. El ()nombre del conjunto que rodea es puramente superfluo. Toda la expresión se interpreta como sizeof my_arr[0]. Esto es equivalente a tu anterior sizeof(my_arr[0]).

(Esto significa, por cierto, que su anterior sizeof(my_arr[0])también contiene un par de superfluos ()).

Es un concepto erróneo bastante generalizado que sizeofla sintaxis de alguna manera requiere un par de ()argumentos. Este concepto erróneo es lo que confunde la intuición de las personas al interpretar expresiones como sizeof(my_arr)[0].


1
La primera versión existe para que pueda verificar el tamaño de un número entero en general en la máquina (¡desde atrás cuando ni siquiera había máquinas de 64 bits!), Pero intno es una expresión válida, por lo que no puede usar el segunda forma con ella.
NH.

25

[]tener una mayor precedencia que sizeof. Entonces sizeof(my_arr)[0]es lo mismo que sizeof((my_arr)[0]).

Aquí hay un enlace a una tabla de precedencia.


8

Estás utilizando la versión del sizeofoperador que toma una expresión como parámetro. A diferencia del que toma un tipo, no requiere paréntesis. Por lo tanto, el operando es simple (my_arr)[0], con paréntesis siendo redundante.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.