Question

Considérez ce code ;

#define A 5
#define B 3

int difference = A - B;

la valeur de « différence » est-elle codée en dur comme « 2 » au moment de la compilation, ou est-elle calculée au moment de l'exécution ?

Était-ce utile?

La solution

Le A et B les macros sont un peu une distraction.Ce:

#define A 5
#define B 3

int difference = A - B;

est exactement équivalent à ceci :

int difference = 5 - 3;

alors parlons de ce dernier.

5 - 3 est un expression constante, qui est une expression qui "peut être évaluée pendant la traduction plutôt que lors de l'exécution, et peut donc être utilisée partout où peut se trouver une constante".C'est aussi une *expression constante entière".Par exemple, une étiquette de cas doit être une expression constante entière, vous pouvez donc écrire ceci :

switch (foo) {
    case 2: /* this is a constant */
    ...
}

ou ca:

switch (foo) {
    case 5 - 3: /* this is a constant expression */
    ...
}

Mais notez que la définition dit qu'il peut être évalué pendant la traduction, pas que cela doive l'être.Certains contextes nécessitent des expressions constantes, et dans ces contextes, l'expression doit être évalué au moment de la compilation.

Mais en supposant que difference est déclaré dans une fonction, l'initialiseur ne fait pas partie de ces contextes.

Tout compilateur valant ce que vous payez (même s'il est gratuit) réduira 5 - 3 à 2 au moment de la compilation et générer du code qui stocke la valeur 2 dans difference.Mais ce n’est pas obligatoire.La norme C précise le comportement de programmes ;il ne précise pas comment ce comportement doit être implémenté.Mais il est prudent de supposer que quel que soit le compilateur que vous utilisez, il remplacera 5 - 3 par 2.

Même si vous écrivez :

int difference = 2;

un compilateur pourrait légalement générer du code qui charge la valeur 5 dans un registre, soustrait 3 à partir de celui-ci et stocke le contenu du registre dans difference.Ce serait une chose idiote à faire, mais la norme linguistique ne l'exclut pas.

Tant que le résultat final est celui difference a la valeur 2, la norme linguistique ne se soucie pas de la manière dont cela est fait.

Par contre, si vous écrivez :

switch (foo) {
    case 5 - 3: /* ... */
    case 2:     /* ... */
}

puis le compilateur doit calculez le résultat afin qu'il puisse diagnostiquer l'erreur (vous ne pouvez pas avoir deux étiquettes de cas avec la même valeur.

Enfin, si vous définissez difference à la portée du fichier (en dehors de toute fonction), puis la valeur initiale fait il faut être constant.Mais la véritable distinction dans ce cas n'est pas de savoir si 5 - 3 sera évalué au moment de la compilation, il s'agit de savoir si vous êtes autorisé pour utiliser une expression non constante.

Référence:La dernière version de la norme C 2011 est N1570 (grand PDF);les expressions constantes sont discutées dans la section 6.6.

Autres conseils

La norme ne précise pas ce genre de chose.Cela ne dit rien sur de potentielles optimisations comme celle-ci (et pour cause).Une norme définit la sémantique, pas la mise en œuvre).

Pourquoi ne pas regarder le démontage de votre compilateur ?Cela vous donnera une réponse définitive.

...

Alors faisons ça.

Voici le résultat de VC++ 10 :

#include <iostream>

#define A 5
#define B 3

int main() {
    int x = A - B;
    std::cout << x;  // make sure the compiler doesn't toss it away
010A1000  mov         ecx,dword ptr [__imp_std::cout (10A2048h)]  
010A1006  push        2  
010A1008  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (10A2044h)]  
    return 0;
010A100E  xor         eax,eax  

Comme vous pouvez le voir, cela vient de remplacer l'occurrence de x avec une valeur statique de 2 et l'a poussé sur la pile pour l'appel à cout.Il n'a pas évalué l'expression au moment de l'exécution.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top