Por que o sizeof (x ++) não incrementa x?

Aqui está o código compilado no dev c ++ windows:

#include  int main() { int x = 5; printf("%d and ", sizeof(x++)); // note 1 printf("%d\n", x); // note 2 return 0; } 

Espero que x seja 6 depois de executar a nota 1 . No entanto, a saída é:

 4 and 5 

Alguém pode explicar por que x não incrementa após a nota 1 ?

Do padrão C99 (a ênfase é minha)

6.5.3.4/2

O operador sizeof produz o tamanho (em bytes) de seu operando, que pode ser uma expressão ou o nome entre parênteses de um tipo. O tamanho é determinado pelo tipo do operando. O resultado é um inteiro. Se o tipo do operando for um tipo de matriz de tamanho variável, o operando é avaliado; caso contrário, o operando não é avaliado e o resultado é uma constante inteira.

sizeof é um operador em tempo de compilation, portanto, no momento da compilation sizeof e seu operando, é substituído pelo valor do resultado. O operando não é avaliado (exceto quando é uma matriz de tamanho variável); apenas o tipo de resultado é importante.

 short func(short x) { // this function never gets called !! printf("%d", x); // this print never happens return x; } int main() { printf("%d", sizeof(func(3))); // all that matters to sizeof is the // return type of the function. return 0; } 

Saída:

 2 

tão short ocupa 2 bytes na minha máquina.

Alterando o tipo de retorno da function para double :

 double func(short x) { // rest all same 

dará 8 como saída.

sizeof(foo) tenta realmente descobrir o tamanho de uma expressão em tempo de compilation:

6.5.3.4:

O operador sizeof produz o tamanho (em bytes) de seu operando, que pode ser uma expressão ou o nome entre parênteses de um tipo. O tamanho é determinado pelo tipo do operando. O resultado é um inteiro. Se o tipo do operando for um tipo de matriz de tamanho variável, o operando é avaliado; caso contrário, o operando não é avaliado e o resultado é uma constante inteira.

Resumindo: arrays de comprimento variável, executados em tempo de execução. (Nota: Matrizes de Comprimento Variável são uma característica específica – não arrays alocados com malloc(3) .) Caso contrário, apenas o tipo da expressão é computado, e isso em tempo de compilation.

sizeof é um operador embutido em tempo de compilation e não é uma function. Isso fica muito claro nos casos em que você pode usá-lo sem os parênteses:

 (sizeof x) //this also works 

Nota

Essa resposta foi mesclada de uma duplicata, o que explica a data final.

Original

Exceto por matrizes de comprimento variável, sizeof não avalia seus argumentos. Podemos ver isso no rascunho da seção padrão C99 6.5.3.4 O 6.5.3.4 parágrafo do operador 2, que diz:

O operador sizeof produz o tamanho (em bytes) de seu operando, que pode ser uma expressão ou o nome entre parênteses de um tipo. O tamanho é determinado pelo tipo do operando. O resultado é um inteiro. Se o tipo do operando for um tipo de matriz de tamanho variável, o operando é avaliado; caso contrário, o operando não é avaliado e o resultado é uma constante inteira.

Um comentário ( agora removido ) perguntou se algo como isso avaliaria em tempo de execução:

 sizeof( char[x++] ) ; 

e, de fato, algo assim também funcionaria ( veja os dois ao vivo ):

 sizeof( char[func()] ) ; 

uma vez que ambos são arrays de comprimento variável. Embora eu não veja muito uso prático em nenhum deles.

Observe que as matrizes de comprimento variável são abordadas no rascunho da seção padrão C99 . 6.7.5.2 , parágrafo 4 :

[…] Se o tamanho for uma expressão constante inteira e o tipo de elemento tiver um tamanho constante conhecido, o tipo de matriz não é um tipo de matriz de comprimento variável; caso contrário, o tipo de matriz é um tipo de matriz de comprimento variável.

Atualizar

Em C11 a resposta muda para o caso do VLA, em certos casos não é especificado se a expressão de tamanho é avaliada ou não. Da seção 6.7.6.2 que diz:

[…] Onde uma expressão de tamanho é parte do operando de um operador sizeof e alterar o valor da expressão de tamanho não afetaria o resultado do operador, não é especificado se a expressão de tamanho é avaliada ou não.

Por exemplo, em um caso como este ( veja ao vivo ):

 sizeof( int (*)[x++] ) 

Como o operando do sizeof operador não é avaliado, você pode fazer isso:

 int f(); //no definition, which means we cannot call it int main(void) { printf("%d", sizeof(f()) ); //no linker error return 0; } 

Demonstração online: http://ideone.com/S8e2Y

Ou seja, você não precisa definir a function f se ela for usada somente em sizeof . Essa técnica é usada principalmente na metaprogramação de modelos C ++, pois, mesmo em C ++, o operando de sizeof não é avaliado.

Por que isso funciona? Ele funciona porque o operador sizeof não opera em valor , em vez disso, ele opera no tipo da expressão. Então, quando você escreve sizeof(f()) , ele opera no tipo da expressão f() , e que não é nada além do tipo de retorno da function f . O tipo de retorno é sempre o mesmo, não importa qual valor a function retornaria se fosse realmente executada.

Em C ++, você pode até mesmo isso:

 struct A { A(); //no definition, which means we cannot create instance! int f(); //no definition, which means we cannot call it }; int main() { std::cout < < sizeof(A().f())<< std::endl; return 0; } 

No entanto, parece que, em sizeof , estou criando primeiro uma instância de A , escrevendo A() e, em seguida, chamando a function f na instância, escrevendo A().f() , mas isso não acontece.

Demonstração: http://ideone.com/egPMi

Aqui está outro tópico que explica algumas outras propriedades interessantes de sizeof :

  • tamanho de tomar dois argumentos

A execução não pode acontecer durante a compilation. Então ++i / i++ não acontecerá. Também sizeof(foo()) não executará a function, mas retornará o tipo correto.

sizeof() operador sizeof() fornece apenas o tamanho do tipo de dados, não avalia elementos internos.