¿Por qué sizeof (x ++) no incrementa x?

Aquí está el código comstackdo en las ventanas dev c ++:

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

Espero que x sea ​​6 después de ejecutar la nota 1 . Sin embargo, el resultado es:

 4 and 5 

¿Alguien puede explicar por qué x no aumenta después de la nota 1 ?

Del estándar C99 (el énfasis es mío)

6.5.3.4/2

El operador sizeof produce el tamaño (en bytes) de su operando, que puede ser una expresión o el nombre entre paréntesis de un tipo. El tamaño se determina a partir del tipo de operando. El resultado es un entero. Si el tipo del operando es un tipo de matriz de longitud variable, se evalúa el operando; de lo contrario, el operando no se evalúa y el resultado es una constante entera.

sizeof es un operador en tiempo de comstackción, por lo que en el momento de la comstackción sizeof y su operando se reemplazan por el valor del resultado. El operando no se evalúa (excepto cuando se trata de una matriz de longitud variable); solo importa el tipo de resultado.

 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; } 

Salida:

 2 

como short ocupa 2 bytes en mi máquina.

Cambiar el tipo de devolución de la función al double :

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

dará 8 como salida.

sizeof(foo) intenta realmente descubrir el tamaño de una expresión en tiempo de comstackción:

6.5.3.4:

El operador sizeof produce el tamaño (en bytes) de su operando, que puede ser una expresión o el nombre entre paréntesis de un tipo. El tamaño se determina a partir del tipo de operando. El resultado es un entero. Si el tipo del operando es un tipo de matriz de longitud variable, se evalúa el operando; de lo contrario, el operando no se evalúa y el resultado es una constante entera.

En resumen: matrices de longitud variable, se ejecutan en tiempo de ejecución. (Nota: las matrices de longitud variable son una característica específica, no las matrices asignadas con malloc(3) . De lo contrario, solo se calcula el tipo de la expresión, y eso en tiempo de comstackción.

sizeof es un operador incorporado en tiempo de comstackción y no es una función. Esto queda muy claro en los casos en que puede usarlo sin el paréntesis:

 (sizeof x) //this also works 

Nota

Esta respuesta se fusionó a partir de un duplicado, lo que explica la fecha tardía.

Original

A excepción de las matrices de longitud variable sizeof no evalúa sus argumentos. Podemos ver esto en el borrador del estándar C99 sección 6.5.3.4 El tamaño del operador párrafo 2 que dice:

El operador sizeof produce el tamaño (en bytes) de su operando, que puede ser una expresión o el nombre entre paréntesis de un tipo. El tamaño se determina a partir del tipo de operando. El resultado es un entero. Si el tipo del operando es un tipo de matriz de longitud variable, se evalúa el operando; de lo contrario, el operando no se evalúa y el resultado es una constante entera.

Un comentario ( ahora eliminado ) pregunta si algo así se evaluaría en el tiempo de ejecución:

 sizeof( char[x++] ) ; 

y de hecho lo haría, algo como esto también funcionaría ( Véalos a ambos en vivo ):

 sizeof( char[func()] ) ; 

ya que ambas son matrices de longitud variable. Aunque, no veo mucho uso práctico en ninguno de los dos.

Tenga en cuenta que las matrices de longitud variable están cubiertas en el borrador de la sección estándar del C99 6.7.5.2 matriz, párrafo 4 :

[…] Si el tamaño es una expresión constante entera y el tipo de elemento tiene un tamaño constante conocido, el tipo de matriz no es un tipo de matriz de longitud variable; de lo contrario, el tipo de matriz es un tipo de matriz de longitud variable.

Actualizar

En C11 la respuesta cambia para el caso de VLA, en ciertos casos no se especifica si la expresión de tamaño se evalúa o no. Desde la sección 6.7.6.2 Array declarators que dice:

[…] Donde una expresión de tamaño es parte del operando de un operador sizeof y cambiar el valor de la expresión de tamaño no afectaría el resultado del operador, no se especifica si la expresión de tamaño se evalúa o no.

Por ejemplo, en un caso como este ( véalo en vivo ):

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

Como el operando del operador sizeof no se evalúa, puede hacer esto:

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

Demostración en línea: http://ideone.com/S8e2Y

Es decir, no necesita definir la función f si se usa solo en sizeof . Esta técnica se usa principalmente en la metaprogtwigción de plantillas C ++, ya que incluso en C ++, el operando de sizeof no se evalúa.

¿Por qué funciona esto? Funciona porque el operador sizeof no funciona con el valor , sino que opera con el tipo de expresión. Entonces cuando se escribe sizeof(f()) , opera en el tipo de la expresión f() , y que no es más que el tipo de retorno de la función f . El tipo de devolución es siempre el mismo, sin importar el valor que devolvería la función si realmente se ejecuta.

En C ++, puedes incluso esto:

 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; } 

Sin embargo, parece que, en sizeof , primero estoy creando una instancia de A , escribiendo A() , y luego llamando a la función f en la instancia, escribiendo A().f() , pero eso no ocurre.

Demostración: http://ideone.com/egPMi

Aquí hay otro tema que explica algunas otras propiedades interesantes de sizeof :

  • sizeof tomando dos argumentos

La ejecución no puede ocurrir durante la comstackción. Entonces ++i / i++ no sucederá. También sizeof(foo()) no ejecutará la función sino que devolverá el tipo correcto.

sizeof() operador sizeof() da el tamaño del tipo de datos, no evalúa los elementos internos.