2010-06-22 69 views
0

下面是我不明白的代碼。查詢C中的激活記錄

#include<stdio.h> 

int main(int argc, char *argv[]) 
{ 
     int num; 

     printf("\n Number: "); 
     scanf("%d", &num); 

     if (num >= 0) 
     { 
      int abs = num; 
     } 
     else 
     { 
      int abs = -num; 
     } 

     { 
      int abs; 
      printf("\n Values are %d %d", num ,abs); 
     } 
     return 0; 
} 

當我輸入一個號碼爲4,輸出爲Values are 4 4
當我輸入一個號碼爲-4,輸出Values are -4 4

我無法理解它是如何能夠打印絕對值?。在if循環和else循環中定義的變量abs應該在退出後被釋放。

請讓我知道。

問候, darkie

回答

0

熱鬧代碼編譯。

它依賴於這樣的事實,即由於編譯器的優化,abs的全部三個定義將被分配到堆棧上的相同位置。

第三個abs必須是隨機的garbag,垃圾變成了前一個同名變量的結果(名字無關緊要)。

1

這些變量在棧中分配但你沒有修改的話,我的意思是你沒有走出的功能,所以呢,編程,你會得到一個「新'abs'int在最後的代碼塊中,但實際上,這個「新」的'abs'int在舊'abs'(在堆棧上)的位置,因此它的默認值是相同的。

+0

您確定這是原因嗎?我的意思是,你怎麼知道新的'abs'和old'abs'位於堆棧的同一個地址? – 2010-06-22 21:07:11

+0

是的,我確定。 Google爲一款名爲Olly Debugger的免費應用程序。打開你的應用程序,或類似Notepad.exe。它會停留在節目的開始位置。在Olly屏幕的底部,您會看到兩個面板 - 左邊是程序的內存,右邊是原始的,右邊是您看到的原始堆棧。現在多次點擊F7並查看堆棧更改。閱讀有關wikipedia上的「stack」以瞭解更多信息。一旦你明白了,你就會完全理解我的回答。如果需要,詢問更多。 – Poni 2010-06-22 22:20:33

+0

順便說一句 - 我無法用MSVC++ 2008編譯器(不是調試版本或者發行版本)重現這種行爲,它告訴我們這是一種依賴於編譯器的行爲。 – Poni 2010-06-22 22:30:43

6

你是絕對正確的。

您是否看到最後一次聲明int abs的最後一個塊?請注意,abs未初始化,並且使用未初始化的變量會生成未定義的結果。使用你特定的編譯器,只是碰巧你運氣不佳,並且新的abs所在的內存塊仍然包含其(過期)先前範圍的結果。

0

您正在printf中使用未初始化的abs值。 C語言標準並不要求它是特別的,因爲它是未初始化的。它可能是0或1,或者-32765

在這種特殊情況下,您可能會得到相同的編號,因爲編譯後的代碼正在重複使用寄存器來獲取abs的臨時值,並且該寄存器再次用於您的abs在printf塊中變量。

您可以查看反彙編代碼,以確切瞭解編譯器在機器指令方面所做的工作。

+0

反彙編代碼? – 2010-06-22 20:45:40

+0

只是從冗餘部門的一小部分...我的意思是反彙編。或者是「反彙編代碼」一個問題? 編譯器編譯爲機器指令時,大多數工具鏈都有一些工具可以將指令反彙編成某種形式的更易讀的彙編語言,因此您可以看到編譯器決定在低級別下使用C代碼做些什麼。 (道歉,如果我是聾啞人,你已經知道......) – Digikata 2010-06-22 23:48:52

1

這就是所謂的「未定義的行爲」。

當您聲明absprintf時,您會收到「堆棧垃圾」。

它的工作原理是這樣的:

if (num >= 0) { 
    create 'abs' at memory address N, put 'num' in it. 
    destroy 'abs' // but leave the 'garbage' at memory address N 
} else { 
    create 'abs' at memory address N, put '-num' in it. 
    destroy 'abs' // but leave the 'garbage' at memory address N 
} 

{ 
    create 'abs' at memory address N, don't put anything in it. 
    // your compiler has decided it will reuse N. That's a valid choice. 
    // your compiler has decided it will not zero the memory at address N. That's valid. 
    read whatever was at 'abs'. // it's whatever was assigned in the conditional. 
} 

始終以-Wall :)

+0

編譯器選項+1 -WLLL – 2010-06-22 20:46:31