¿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
( sizeof( my_arr ) )[ 0 ]
falla.Respuestas:
sizeof
No es una función. Es un operador unario como!
o~
.sizeof(my_arr)[0]
analiza comosizeof (my_arr)[0]
, que es solosizeof 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 comosizeof (*((a[i])++))
(los operadores de postfix[]
y++
se aplicana
primero, luego los operadores de prefijo*
ysizeof
).(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 lasizeof
sintaxis).fuente
sizeof
ser un operador unario."... parses as sizeof (my_arr[0])"
? Solo agregar un espacio realmente no cambia nada.sizeof((my_array)[0])
lugar, recomendaríasizeof
tiene dos "versiones":sizeof(type name)
ysizeof 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 lasizeof
sintaxis en sí.Como
my_arr
el compilador lo conoce como un nombre de objeto, no como un nombre de tipo,sizeof(my_arr)[0]
el compilador lo ve realmente comosizeof
aplicado 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 comosizeof my_arr[0]
. Esto es equivalente a tu anteriorsizeof(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
sizeof
la 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 comosizeof(my_arr)[0]
.fuente
int
no es una expresión válida, por lo que no puede usar el segunda forma con ella.[]
tener una mayor precedencia quesizeof
. Entoncessizeof(my_arr)[0]
es lo mismo quesizeof((my_arr)[0])
.Aquí hay un enlace a una tabla de precedencia.
fuente
Estás utilizando la versión del
sizeof
operador 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.fuente