2009-09-26 2 views
1

Следующий код генерирует y, это ответ, но я никогда не назначал 42 на y, как может быть 42?Неназначенная переменная имеет значение

#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

Вы должны спросить «как это могло бы быть не * 42»? –

+0

Что вы ожидаете от y? – recursive

+0

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

ответ

12

Это связано с тем, как называются функции. Когда вызывается doit1, аргумент a (42) помещается в стек вызовов, а b (также 42) находится прямо над ним. Когда вы выходите из doit1 и введите doit2, x и y находятся на том же месте a и b были в doit1. Поскольку ни один из них не инициализирован, они просто используют любое значение уже в этом месте - 42 в вашем случае. Конечно, в зависимости от оптимизации это может быть не всегда, но это довольно хорошая ставка, что и будет.

В Википедии есть достойная статья на how the call stack works.

10

Там будет несколько ответов, указывающих из проблем, с штабелями/регистрами/временными переменными, но я укажу, что если вы компилируете с оптимизациями, нет ответа.

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

Кроме того, когда вы сделать не Оптимизировать, ответ кажется зависит от компилятора:

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

В НКУ, в неоптимизированному Результаты doit2 в этой сборке:

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 

При оптимизации мы даже не сравниваем с 42:

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

Значения x и y не определены, они просто находятся в том месте, где они выделены.

В вашем случае переменная y либо выделена в том же месте, где параметр a или переменная b были в методе doit1. Это происходит в используемом компиляторе с определенными настройками, которые вы использовали. Любая другая комбинация может дать другой результат, так как есть много вещей, которые могут быть реализованы различными способами:

  • doit1 функция может существовать в виде функции или быть встраиваемой.
  • Параметр функции doit1 может быть отправлен либо в стек, либо в регистр.
  • Переменная b в doit1 может существовать или нет. Поскольку он никогда не использовался, компилятор может удалить оператор.
  • Любая из переменных x и y в doit2 может быть выделена в стеке или в регистре в любой комбинации.
Смежные вопросы