c - array - sizeof string
¿Por qué sizeof(my_arr)[0] compila e igual sizeof(my_arr[0])? (4)
¿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 a 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
Está utilizando la versión del operador
sizeof
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 simplemente
(my_arr)[0]
, y los paréntesis son redundantes.
[]
tienen mayor precedencia que
sizeof
.
Entonces
sizeof(my_arr)[0]
es lo mismo que
sizeof((my_arr)[0])
.
Here hay un enlace a una tabla de precedencia.
sizeof
no es una función.
Es un operador unario como
!
o
~
.
sizeof(my_arr)[0]
analiza como
sizeof (my_arr)[0]
, que es simplemente
sizeof my_arr[0]
con paréntesis redundantes.
Esto es igual que
!(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 a primero, 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 padres y parte de la sintaxis de
sizeof
).
sizeof
tiene dos "versiones":
sizeof(type name)
y
sizeof expression
.
El primero requiere un par de
()
alrededor de su argumento.
Pero el último, el que tiene una expresión como argumento, no tiene
()
alrededor de su argumento.
Cualquier cosa
()
que use en el argumento se ve como parte de la expresión del argumento, no como parte de la sintaxis del mismo
sizeof
.
Dado que el compilador conoce
my_arr
como un nombre de objeto, no como un nombre de tipo, el compilador ve realmente su
sizeof(my_arr)[0]
como
sizeof
aplicado a una expresión:
sizeof (my_arr)[0]
, donde
(my_arr)[0]
es la expresión del argumento.
El
()
rodea el nombre de la matriz es puramente superfluo.
Toda la expresión se interpreta como
sizeof my_arr[0]
.
Esto es equivalente a su
sizeof(my_arr[0])
anterior de
sizeof(my_arr[0])
.
(Esto significa, por cierto, que su
sizeof(my_arr[0])
anterior de
sizeof(my_arr[0])
también contiene un par de superfluos
()
.)
Es una idea errónea bastante generalizada que la sintaxis de
sizeof
alguna manera requiere un par de
()
alrededor de su argumento.
Este concepto erróneo es lo que confunde la intuición de las personas al interpretar expresiones como
sizeof(my_arr)[0]
.