2009-09-26 8 views
1

Le code suivant génère y est la réponse, mais je n'ai jamais assigné 42 à y, comment pourrait-il être 42?La variable non affectée a une valeur

#include <stdio.h> 

void doit2(void) 
{ 
    int x; 
    int y; 
    if (x == 42) 
    { 
     printf("x is the answer\n"); 
    } 
    else if (y == 42) 
    { 
     printf("y is the answer\n"); 
    } 
    else 
    { 
     printf("there is no answer\n"); 
    } 
} 

void doit1(int a) 
{ 
    int b = a; 
} 

int main(void) 
{ 
    doit1(42); 
    doit2(); 
} 
+4

Vous devriez demander "comment pourrait-il * pas * être 42"? –

+0

Qu'attendez-vous de y? – recursive

+0

Dupliquer: http://stackoverflow.com/questions/1225788/uninitialized-values-being-initialized/1225790 – GManNickG

Répondre

12

Ceci est dû à la façon dont les fonctions sont appelées. Lorsque doit1 est appelé, l'argument a (42) est placé sur la pile d'appel, et b (également 42) est juste au-dessus. Lorsque vous quittez doit1 et entrez doit2, et y sont à la même place a et b étaient dans doit1. Étant donné que ni l'un ni l'autre n'est initialisé, ils utilisent simplement la valeur qui existe déjà à cet endroit - 42 dans votre cas. Bien sûr, en fonction de l'optimisation, il se peut que cela ne se produise pas, mais c'est un très bon pari que ce soit le cas.

Wikipedia a un article décent sur how the call stack works.

10

Il va être quelques réponses pointant sur des problèmes avec les piles/registres/variables temporaires, mais je vous signale que si vous compilez avec des optimisations, il n'y a pas de réponse.

 
$ gcc -O3 42.c -o 42 
$ ./42 
there is no answer 
$ gcc -O2 42.c -o 42 
$ ./42 
there is no answer 

De plus, lorsque vous ne pas optimize, la réponse semble dépend de votre compilateur:

 
$ gcc 42.c -o 42 
$ ./42 
x is the answer 
$ tcc -run 42.c 
y is the answer 

Dans GCC, les non optimisés résultats de doit2 dans cette assemblée:

doit2: 
     pushl %ebp 
     movl %esp, %ebp 
     subl $24, %esp 
     cmpl $42, -4(%ebp) 
     jne  .L2 
     movl $.LC0, (%esp) 
     call puts 
     jmp  .L5 
.L2: 
     cmpl $42, -8(%ebp) 
     jne  .L4 
     movl $.LC1, (%esp) 
     call puts 
     jmp  .L5 
.L4: 
     movl $.LC2, (%esp) 
     call puts 
.L5: 
     leave 
     ret 

Lorsque optimisé, nous ne comparons même pas avec 42:

doit2: 
     pushl %ebp 
     movl %esp, %ebp 
     subl $8, %esp 
     movl $.LC2, (%esp) 
     call puts 
     leave 
     ret 
1

Les valeurs de x et y ne sont pas définies, elles sont juste ce qui se passe à l'emplacement où elles sont allouées.

Dans votre cas, la variable y est allouée au même endroit où le paramètre a ou la variable b étaient dans la méthode doit1. Cela se produit dans le compilateur que vous avez utilisé, avec les paramètres spécifiques que vous avez utilisés. Toute autre combinaison peut donner un résultat différent, car il y a beaucoup de choses qui peuvent être mises en œuvre de différentes façons:

  • La fonction doit1 pourrait exister en fonction ou être inline.
  • Le paramètre de la fonction doit1 peut être envoyé sur la pile ou dans un registre. La variable b dans doit1 peut exister ou non. Comme il n'est jamais utilisé, le compilateur pourrait supprimer l'instruction.
  • L'une des variables x et y dans doit2 pourrait être affectée sur la pile ou dans un registre, dans n'importe quelle combinaison.
Questions connexes