2009-09-26 91 views
1

以下代码生成y是答案,但我从未将42赋值给y,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,xy是在相同的地方abdoit1。既然它们都没有被初始化,它们只是使用那个位置已经有的值 - 在你的情况下。当然,根据优化情况,这可能不是总是发生,但它是一个相当不错的选择。

维基百科在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 

在GCC中,未优化 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函数的参数可以在堆栈或寄存器中发送。
  • doit1中的变量b可能存在与否。由于它从未使用,编译器可以删除该语句。
  • xy中的任一个都可以在栈中或在寄存器中以任何组合分配。