2014-02-18 86 views
1

我很難理解這兩個源代碼的打印值。簡單的C代碼片段

#include<stdio.h> 
    void a(void){ 
    int a; 
    a++; 
    printf("%d\n",a); 
} 

int main(void){ 
    a(); 
    a(); 
    a(); 
    return 0; 
} 

爲什麼這個代碼打印出 「1 2 3」,而第二個:

#include<stdio.h> 
void a(void){ 
    int a; 
    a++; 
    printf("%d\n",a); 
} 

int main(void){ 
    int b; 
    printf("%d\n",b); 
    a(); 
    a(); 
    a(); 
    return 0; 
} 

打印出:「0,垃圾值,相同的垃圾值1,相同垃圾值+ 2「。

不應該爲主函數(或任何其他函數)中的任何未初始化的對象分配一個隨機(垃圾)值?

更新:我覺得解釋「變量是未初始化的,所以他們可以有其他程序的任何剩餘值 - > UB」是不夠的。我可以複製粘貼相同的源代碼100次,仍然可以得到0的打印值。我正在使用gcc 4.4.3。

+1

不定值。無論堆棧是什麼,你都會得到。在第二種情況下,由於通過在'main'中添加局部變量來更改堆棧,所以它不同。在第一種情況下,在'a'的地址處堆棧中的值是'0'。 '0'可以是隨機的'0'。 – lurker

+0

在第一種情況下,可能是因爲編譯器決定在'0'處「初始化」a的值,所以你會得到一組合理的值。這種行爲將是編譯器特定的。請將您使用的編譯器添加到您的問題中。 – abiessu

+0

@abiessu;那不是那個UB嗎? – haccks

回答

5

未初始化的自動變量的值是不確定的,所以如果你沒有在具有特定標誌集的特定機器上討論特定編譯器,那麼它確實是不可預測的。即使你談論一個非常具體的平臺和設置,你仍然可能得不到可重現的結果。

在一些非常特殊的情況下,您可以進行預測,並且presentation Deep C會對此進行一般性討論,並在幻燈片71的範圍內涵蓋此特定情況。

在現代系統上,自動變量通常會分配在堆棧上,並且您可能會得到相同的內存位置,因此您會看到三個連續的值。但是你不應該依賴這種行爲,並且使用未初始化的變量是undefined behavior,並且結果是不可預測的。

C99 draft standard告訴我們在第6.7.8初始化款是:

如果具有自動存儲時間的對象沒有初始化,它的價值是不確定的。

,並告訴我們在indeterminate value定義:

或者未指定值或陷阱表示

更新

什麼是不確定的行爲?從最嚴格的意義上講,C標準並沒有強加要求的行爲,它是標準的構建。它是在標準草案中定義的部分3.4.3

行爲,一旦或錯誤數據的使用非便攜式的或錯誤的程序構建體, 指此國際標準並沒有規定要求

,並具有以下說明:

可能存在的未定義的行爲範圍包括忽略完全具有不可預知的結果的情況,在翻譯或程序執行過程中表現爲有記錄的人(有或者沒有發佈診斷消息)的環境特徵,終止翻譯或執行(通過發佈診斷消息)。

在一天結束時,在設計高效的語言和安全的語言之間進行權衡,從What Every C Programmer Should Know About Undefined Behavior #1/3轉述。

這裏有更多的聯繫,更好地理解未定義行爲:

+0

因此,未定義的行爲實際上來自它可以根據編譯器,機器,標誌,優化而產生不同結果的事實嗎? – Dragos276

+0

@ Dragos276這些是一些主要的變量,可能會使用[在線編譯器](http://stackoverflow.com/questions/3916000/online-c-compiler-and-evaluator)產生一個測試用例,它是一致的並深入到大會並確定爲什麼,但你希望從中獲得什麼? –

+0

我試圖理解2個源代碼的行爲,除了「從內存中隨機分配的數字」之外,UB實際上還有什麼意義。機器自己特定的助記符是否對這種隨機行爲負責? – Dragos276

2

爲什麼這段代碼打印出 「1 2 3」

它調用未定義的行爲。什麼事情都可能發生。使用未初始化的變量調用UB。

不應該爲主函數(或任何其他functon)中的任何未初始化的對象分配一個隨機(垃圾)值?

是的。但是垃圾價值可能是任何事情。你無法預測它。

+0

加油。這不是一個解釋。你可以做得更好。 – Carpetsmoker

+0

@Carpetsmoker;嚴。我正在這樣做。 – haccks

+0

@abiessu;然後請張貼您的答案。我將學習如何發佈*更好*的答案。 – haccks

2

int a;在第一個代碼中,您還沒有初始化a這意味着它包含垃圾值。上面的代碼片斷可能會有不同的打印垃圾值。

未初始化變量是一個已聲明的變量,但在使用前未設置爲明確的已知值。它將有some value,但不是可預測的。因此,這是程序錯誤,是軟件中常見的錯誤來源。

2

由於所有的值都是未初始化的,它們可以包含任何東西。

所以你的輸出是不可預測的,因爲你不知道變量有什麼值。

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

+0

所以你說什麼是「未定義的行爲」這個詞來源於這樣一個事實,即所聲明變量的值有時可能有0或隨機值,這取決於源代碼的結構? – Dragos276

+0

你的句子的第一部分是正確的。但是這個未定義的事實並不是來自代碼的結構,而是來自於你在不知道它的內容的情況下訪問內存的事實。 – OlivierLi

+0

@ Dragos276:變量未初始化。這意味着它們沒有任何價值,並且它們分配給內存位置的任何內容都是它們開始的值。 – abiessu

1

它既是undefined bahaviour。在第一個例子中,它恰好爲0,而在本地變量中爲0。然後在第二個例子中移位局部變量位置處的隨機值(由於主局部變量而移位)。

從OS中檢索內存頁時通常是零,所以它很可能是語言運行庫或某些其他前置主代碼的堆棧佔用空間。因此在重複運行中看起來可以預見你。它可能在不同的機器/編譯器等上完全不同。