2009-09-26 93 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中的任一個都可以在棧中或在寄存器中以任何組合分配。