Por que esse código é compilado?
_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, "");
As duas primeiras afirmações estão obviamente corretas, mas eu esperava que a última linha falhasse, pois meu entendimento é que isso sizeof()
deve ser avaliado como um literal inteiro, que não pode ser tratado como uma matriz. Em outras palavras, falharia da mesma maneira que a seguinte linha falha:
_Static_assert(4[0] == 4, "");
Curiosamente, o seguinte não compila (o que deveria estar fazendo a mesma coisa, não?):
_Static_assert(*sizeof(my_arr) == 4, "");
erro: argumento de tipo inválido de unary '*' (tem 'long unsigned int') _Static_assert (* sizeof (my_arr) == 4, "");
Se isso importa, estou usando o gcc 5.3.0
( sizeof( my_arr ) )[ 0 ]
falha.Respostas:
sizeof
não é uma função. É um operador unário como!
ou~
.sizeof(my_arr)[0]
analisa comosizeof (my_arr)[0]
, que é apenassizeof my_arr[0]
com parênteses redundantes.Isto é como
!(my_arr)[0]
analisa como!(my_arr[0])
.Em geral, os operadores de postfix têm precedência mais alta que os operadores de prefixo em C.
sizeof *a[i]++
analisa comosizeof (*((a[i])++))
(os operadores de postfix[]
e++
são aplicadosa
primeiro, depois os operadores de prefixo*
esizeof
).(Esta é a versão da expressão
sizeof
. Há também uma versão de tipo, que recebe um nome de tipo entre parênteses:.sizeof (TYPE)
Nesse caso, os parênteses seriam necessários e parte dasizeof
sintaxe.)fonte
sizeof
ser um operador unário."... parses as sizeof (my_arr[0])"
? Apenas adicionar um espaço não muda nada.sizeof((my_array)[0])
vez disso, eu recomendariasizeof
possui duas "versões":sizeof(type name)
esizeof expression
. O primeiro requer um par de()
argumentos. Mas o último - aquele com uma expressão como argumento - não tem em()
torno de seu argumento. Tudo()
o que você usa no argumento é visto como parte da expressão do argumento, não como parte dasizeof
própria sintaxe.Como
my_arr
é conhecido pelo compilador como um nome de objeto, não um nome de tipo, vocêsizeof(my_arr)[0]
é realmente visto pelo compilador comosizeof
aplicado a uma expressão:,sizeof (my_arr)[0]
onde(my_arr)[0]
está a expressão do argumento. O()
nome ao redor da matriz é puramente supérfluo. A expressão inteira é interpretada comosizeof my_arr[0]
. Isso é equivalente ao seu anteriorsizeof(my_arr[0])
.(Isso significa, aliás, que o seu anterior
sizeof(my_arr[0])
também contém um par de supérfluos()
.)É um equívoco bastante difundido que
sizeof
a sintaxe de alguma forma requer um par de()
argumentos. Esse equívoco é o que engana a intuição das pessoas ao interpretar expressões comosizeof(my_arr)[0]
.fonte
int
não é uma expressão válida; portanto, não é possível usar o segunda forma com ele.[]
tem uma precedência maior quesizeof
. Entãosizeof(my_arr)[0]
é o mesmo quesizeof((my_arr)[0])
.Aqui está um link para uma tabela de precedência.
fonte
Você está usando a versão do
sizeof
operador que aceita uma expressão como parâmetro. Ao contrário do que pega um tipo, ele não requer parênteses. Portanto, o operando é simples(my_arr)[0]
, com os parênteses sendo redundantes.fonte