web-dev-qa-db-fra.com

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

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

#include <stdio.h>

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

Je prévois que x soit 6 après avoir exécuté note 1 . Cependant, le résultat est:

4 and 5

Quelqu'un peut-il expliquer pourquoi x n'augmente pas après note 1 ?

481
Neigyl R. Noval

Du C99 Standard _ (c'est moi qui souligne)

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 par le 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.

511
pmg

sizeof est un opérateur de compilation, donc au moment de la compilation, sizeof et son opérande sont remplacés par la valeur du résultat. L'opérande est non é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.

Modification du type de retour de la fonction en double:

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

donnera 8 en sortie.

178
codaddict

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 un 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 tableau de longueur variable type, l'opérande est évalué; sinon, l'opérande n'est pas évalué et le résultat est un constante entière.

En bref: tableaux de longueur variable, exécutés à l'exécution. (Remarque: Les tableaux de longueur variable sont une caractéristique spécifique - pas les tableaux alloués avec malloc(3).) Sinon, seul le type de l'expression est calculé, à la compilation.

47
sarnold

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 la parenthèse:

(sizeof x)  //this also works
33
hugomg

Remarque

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

Original

À l'exception de tableaux de longueur variable } _ sizeof n'évalue pas ses arguments. Nous pouvons le voir dans le projet de section standard C99 6.5.3.4L'opérateur sizeof paragraph 2 qui dit:

L'opérateur sizeof donne la taille (en octets) de son opérande, qui peut être un 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 tableau de longueur variable type, l'opérande est évalué; sinon, l'opérande n'est pas évalué et le résultat est un constante entière.

Un commentaire (maintenant supprimé) a demandé si quelque chose comme ceci serait évalué au moment de l'exécution:

sizeof( char[x++]  ) ;

et effectivement cela fonctionnerait, quelque chose comme ceci fonctionnerait aussi (VOYEZ 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.

Remarque: les tableaux de longueur variable sont couverts dans le norme C99 section 6.7.5.2Déclarateurs de tableau 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 _ Déclarateurs de tableau qui dit:

[...] Où une expression de taille fait partie de l'opérande d'une taille de opérateur et changer la valeur de l'expression de taille ne serait pas affecter 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 (LE VOIR EN DIRECT):

sizeof( int (*)[x++] )
19
Shafik Yaghmour

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 dans sizeof uniquement. 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 ne fonctionne pas sur value, mais sur type de l'expression. Ainsi, lorsque 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 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 certaines autres propriétés intéressantes de sizeof:

10
Nawaz

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 le type correct.

10
rakesh

sizeof s'exécute au moment de la compilation, mais x++ ne peut être évalué qu'au moment de l'exécution. Pour résoudre ce problème, la norme C++ indique que l'opérande de sizeof n'est pas évalué (sauf pour les VLA). La norme C dit:

Si le type de l'opérande [de sizeof] 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.

0
stackptr

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

0
munna