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

Voici le code compilé dans dev c ++ windows:

#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 le suivant:

 4 and 5 

Quelqu’un peut-il expliquer pourquoi x ne s’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 à la compilation, donc 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 

comme short occupe 2 octets sur ma machine.

Changer le type de retour de la fonction pour double :

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

donnera 8 comme sortie.

sizeof(foo) essaie vraiment de découvrir la taille d’une expression à 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 sont une fonctionnalité spécifique – pas les tableaux alloués avec malloc(3) . Sinon, seul le type de l’expression est calculé et cela au moment de 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

A l’exception des tableaux de longueur variable, sizeof n’évalue pas ses arguments. Nous pouvons le voir à partir du projet de norme C99 section 6.5.3.4 La 6.5.3.4 paragraphe opérateur 2 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 ceci serait évalué à l’exécution:

 sizeof( char[x++] ) ; 

et en effet, quelque chose comme ça fonctionnerait aussi ( Voir 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 longueur variable sont traités dans le projet de norme C99, section 6.7.5.2 , paragraphe 4 :

[…] Si la taille est une expression de type entier 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

Dans C11, la réponse change pour le cas VLA, dans certains cas, il n’est pas spécifié si l’expression de taille est évaluée ou non. À partir de la section 6.7.6.2 Déclarateurs de 6.7.6.2 :

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

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

En d’autres termes, 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 des 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 ne fonctionne pas sur la valeur , mais opère sur le type de l’expression. Donc, quand vous écrivez sizeof(f()) , il opère sur le type de l’expression f() , et 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 renvoyée par la fonction si elle est exécutée.

En C ++, vous pouvez même faire 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, 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 cela ne se produit.

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

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

  • sizeof prendre deux arguments

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

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