Pourquoi sizeof (x ++) n’incrémente-t-il pas x?

Voici le code compilé dans les fenêtres dev c ++:

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

Je pense que x sera 6 après avoir exécuté la note 1 . Cependant, le résultat est:

 4 and 5 

Quelqu’un peut-il expliquer pourquoi x n’incrémente pas après la note 1 ?

De la norme C99 (l’accent est mis sur moi)

6.5.3.4/2

L’opérateur sizeof donne la taille (en octets) de son opérande, qui peut être une expression ou le nom entre parenthèses d’un type. La taille est déterminée à partir du type de l’opérande. Le résultat est un entier. Si le type de l’opérande est un type de tableau de longueur variable, l’opérande est évalué. sinon, l’opérande n’est pas évalué et le résultat est une constante entière.

sizeof est un opérateur de compilation, ainsi, au moment de la compilation, sizeof et son opérande sont remplacés par la valeur du résultat. L’ opérande n’est pas évalué (sauf s’il s’agit d’un tableau de longueur variable); seul le type du résultat compte.

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

Sortie:

 2 

as short occupe 2 octets sur ma machine.

Changer le type de retour de la fonction à double :

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

donnera 8 en sortie.

sizeof(foo) essaie vraiment de découvrir la taille d’une expression au moment de la compilation:

6.5.3.4:

L’opérateur sizeof donne la taille (en octets) de son opérande, qui peut être une expression ou le nom entre parenthèses d’un type. La taille est déterminée à partir du type de l’opérande. Le résultat est un entier. Si le type de l’opérande est un type de tableau de longueur variable, l’opérande est évalué. sinon, l’opérande n’est pas évalué et le résultat est une constante entière.

En bref: tableaux de longueur variable, exécutés à l’exécution. (Remarque: les tableaux de longueur variable constituent une fonctionnalité spécifique – pas les tableaux alloués avec malloc(3) .) Sinon, seul le type de l’expression est calculé, à la compilation.

sizeof est un opérateur intégré à la compilation et n’est pas une fonction. Cela devient très clair dans les cas où vous pouvez l’utiliser sans la parenthèse:

 (sizeof x) //this also works 

Remarque

Cette réponse a été fusionnée à partir d’un duplicata, ce qui explique la date tardive.

Original

À l’exception des tableaux de longueur variable, sizeof n’évalue pas ses arguments. Nous pouvons le voir dans le projet de norme C99, section 6.5.3.4 Le paragraphe 2 de l’ opérateur 6.5.3.4 qui dit:

L’opérateur sizeof donne la taille (en octets) de son opérande, qui peut être une expression ou le nom entre parenthèses d’un type. La taille est déterminée à partir du type de l’opérande. Le résultat est un entier. Si le type de l’opérande est un type de tableau de longueur variable, l’opérande est évalué. sinon, l’opérande n’est pas évalué et le résultat est une constante entière.

Un commentaire ( maintenant supprimé ) demandait si quelque chose comme celui-ci serait évalué au moment de l’exécution:

 sizeof( char[x++] ) ; 

et en effet, quelque chose comme ceci fonctionnerait aussi ( voyez-les tous les deux en direct ):

 sizeof( char[func()] ) ; 

puisqu’ils sont tous deux des tableaux de longueur variable. Bien que, je ne vois pas beaucoup d’utilisation pratique dans l’un ou l’autre.

Notez que les tableaux de longueurs variables sont traités dans le projet de norme C99, section 6.7.5.2 Déclarateurs de 6.7.5.2 , paragraphe 4 :

[…] Si la taille est une expression constante entière et que le type d’élément a une taille constante connue, le type de tableau n’est pas un type de tableau de longueur variable; sinon, le type de tableau est un type de tableau de longueur variable.

Mettre à jour

En C11, la réponse change pour le cas VLA. Dans certains cas, il n’est pas précisé si l’expression de taille est évaluée ou non. De la section 6.7.6.2 Les déclarants de tableau qui dit:

[…] Lorsqu’une expression de taille fait partie de l’opérande d’un opérateur sizeof et que la modification de la valeur de l’expression de taille n’affectera pas le résultat de l’opérateur, il n’est pas précisé si l’expression de taille est évaluée ou non.

Par exemple dans un cas comme celui-ci ( voir en direct ):

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

Comme l’opérande de l’opérateur sizeof n’est pas évalué, vous pouvez le faire:

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

Démo en ligne: http://ideone.com/S8e2Y

Autrement dit, vous n’avez pas besoin de définir la fonction f si elle est utilisée uniquement dans sizeof . Cette technique est principalement utilisée dans la métaprogrammation de modèles C ++, car même en C ++, l’opérande de sizeof n’est pas évalué.

Pourquoi ça marche? Cela fonctionne parce que l’opérateur sizeof n’agit pas sur la valeur , mais sur le type de l’expression. Ainsi, lorsque vous écrivez sizeof(f()) , il agit sur le type de l’expression f() , qui n’est rien d’autre que le type de retour de la fonction f . Le type de retour est toujours le même, quelle que soit la valeur que la fonction renverrait si elle s’exécutait réellement.

En C ++, vous pouvez même ceci:

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

Pourtant, il semble que, dans sizeof , je crée d’abord une instance de A en écrivant A() , puis en appelant la fonction f sur l’instance, en écrivant A().f() , mais rien de tel ne se produit.

Démo: http://ideone.com/egPMi

Voici un autre sujet qui explique quelques autres propriétés intéressantes de sizeof :

  • sizeof prenant deux arguments

L’exécution ne peut pas avoir lieu pendant la compilation. Donc, ++i / i++ ne se produira pas. De plus, sizeof(foo()) n’exécutera pas la fonction mais renverra un type correct.

sizeof() opérateur sizeof() donne uniquement la taille du type de données, il n’évalue pas les éléments internes.