530 votes

Pourquoi sizeof(x++) n'incrémente pas x ?

Voici le code compilé en dev c++ Windows :

#include <stdio.h>

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

J'attends x à 6 après l'exécution de note 1 . Cependant, le résultat est :

4 and 5

Quelqu'un peut-il expliquer pourquoi x ne s'incrémente pas après que note 1 ?

41 votes

Je note que DevC++ utilise un très vieux compilateur obsolète, vous voudrez peut-être passer à un IDE plus récent, par exemple Codeblocks Eclipse ou Visual Studio.

0 votes

Une note pour moi-même : stackoverflow.com/a/21995718 est la bonne réponse.

0 votes

printf("%d and ", sizeof(x++)); // note 1 cause UB, pourquoi s'attendre à des résultats significatifs ? Veuillez lire le printf() ou les sections de la norme C concernant les printf() / fprintf() .

564voto

pmg Points 52636

A partir de la Norme C99 (l'accent est mis par 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.

8 votes

Qu'entendez-vous par type de tableau à longueur variable ? Cela signifie que l'opérande est un tableau ? Dans ce cas, le code n'est pas un tableau. Pouvez-vous m'éclairer sur ce point ?

44 votes

Un tableau de longueur variable est un tableau déclaré dont la taille est une valeur inconnue lors de la compilation. N à partir de stdin et de faire int array[N] . Il s'agit d'une des fonctionnalités de C99, non disponible en C++.

21 votes

@LegendofCage, en particulier cela signifierait que dans quelque chose comme sizeof(int[++x]) (ce qui est vraiment, vraiment une mauvaise idée). ++ a pu être évaluée.

196voto

codaddict Points 154968

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érateur L'opérande est non évaluée (sauf s'il s'agit d'un tableau de longueur variable). type du résultat importe.

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 en double :

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

donnera 8 en sortie.

16 votes

Parfois seulement - si possible au moment de la compilation.

12 votes

-1, car cela est en contradiction avec la réponse acceptée (et correcte) et ne cite pas la norme.

1 votes

La résolution au moment de la compilation de l'opérateur sizeof() présente un avantage certain lorsque l'on travaille avec des chaînes de caractères. Si vous avez une chaîne qui est initialisée comme une chaîne citée, au lieu d'utiliser strlen(), où le tableau de caractères comprenant la chaîne doit être analysé à la recherche du terminateur nul au moment de l'exécution, sizeof(quoted_string) est connu au moment de la compilation, et donc au moment de l'exécution. C'est une petite chose, mais si vous utilisez la chaîne citée dans une boucle des millions et des millions de fois, cela fait une différence significative en termes de performances.

51voto

sarnold Points 62720

sizeof(foo) s'efforce 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 ou le nom parenthésé 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 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. constante entière.

En bref : des tableaux de longueur variable, exécutés au moment de l'exécution. (Remarque : Tableaux de longueur variable sont une caractéristique spécifique -- et non des tableaux alloués avec des malloc(3) .) Dans le cas contraire, seuls les type de l'expression est calculée, et ce au moment de la compilation.

36voto

hugomg Points 29789

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

(sizeof x)  //this also works

1 votes

Mais en quoi cela constitue-t-il une réponse à la question ?

5 votes

@phresnel : C'est juste pour préciser que sizeof est "bizarre" et n'est pas soumis aux règles des fonctions normales. J'ai quand même édité le post pour supprimer la confusion possible avec les opérateurs d'exécution normaux comme (+) et (-).

1 votes

Les sizeof L'opérateur est pas est un opérateur de compilation, il suffit de lui donner un VLA pour qu'il s'en rende compte.

25voto

Shafik Yaghmour Points 42198

Note

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

Original

À l'exception de tableaux de longueur variable taille de n'évalue pas ses arguments. C'est ce que montre la section du projet de norme C99 6.5.3.4 La taille de l'opérateur paragraphe 2 qui dit :

L'opérateur sizeof donne la taille (en octets) de son o ou le nom parenthésé 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 à longueur variable l'opérande est évalué ; sinon, l'opérande n'est pas évalué et le résultat est une constante entière. constante entière.

Un commentaire( maintenant supprimée ) a demandé si une telle chose pouvait être évaluée au moment de l'exécution :

sizeof( char[x++]  ) ;

et c'est effectivement le cas, quelque chose comme ceci fonctionnerait également ( Voir les deux en direct ):

sizeof( char[func()]  ) ;

puisqu'il s'agit dans les deux cas de tableaux de longueur variable. Cependant, je ne vois pas d'utilité pratique à l'un ou à l'autre.

Remarque : les tableaux de longueur variable sont traités dans la section projet de norme C99 section 6.7.5.2 Déclarateurs de tableaux 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 à longueur variable ; sinon, le type de tableau est un type de tableau à longueur variable.

Mise à jour

En C11, la réponse change pour le cas VLA, dans certains cas, il n'est pas précisé si l'expression de la taille est évaluée ou non. De la section 6.7.6.2 Déclarateurs de tableaux qui dit :

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

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

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

0 votes

De quelle manière les sizeof (char[x++]); utiliser la valeur de x pour autre chose que la détermination de la valeur de l'expression x++ et la nouvelle valeur de x qui sont toutes deux normales avec cet opérateur ?

0 votes

@CorleyBrigman la réponse rapide serait b/c the standard says so, mais la raison est b/c we don't know the array size at compile time so we have to evaluate the expression at run-time. Les VLA sont un sujet intéressant, voici deux articles que j'ai rédigés à leur sujet aquí y aquí .

0 votes

@Shafik - ahh, ok, je pense que ma confusion venait du fait que je n'avais pas réalisé char[x++] est un VLA. il ressemble effectivement à un char* à mes yeux inconnus.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X