2010-10-01 181 views
4
int main() 
{ 
    int x=5,y=10,z=15; 
    printf("%d %d %d"); 
    return 0; 
} 

輸出:15 10 5 //在用Turbo C 4.5以下代碼的輸出是什麼?

3 Garbage values in gcc compiler 

我的老師告訴我,當我們定義如int x = 5的變量,Y = 10,Z = 15;它們默認爲自動類型並存儲在堆棧中。當您嘗試打印3個整數值而不使用printf()的名稱時,它將以Turbo C編譯器的LIFO格式打印這3個值。 但是,當我們定義3個整型變量時,我們認爲它們可能不會存儲在連續的內存位置中。因此,當我嘗試在不使用其名稱的情況下打印3個整數值時,編譯器將從堆棧頂部打印任何三個值。輸出將會出現3個垃圾值,如gcc ..

+0

那麼,你的問題是...? – 2010-10-01 14:13:43

+2

找一位新老師。如果他說的不是「這是不確定的行爲,不要做」,他不知道他在說什麼。 – JeremyP 2010-10-01 14:16:02

+0

@Daniel Standage邏輯上正確的是什麼? – Parikshita 2010-10-01 14:19:35

回答

10

此代碼只是表明的Turbo C差在優化代碼,並把堆棧上的一切,而GCC是更積極,並保持它在寄存器或它扔了出去都在一起,因爲這三個變量沒有什麼目的。

無論如何,調用printf需要三個參數而不提供這些參數的模式是錯誤的。

更新:

作爲一個解釋:我假設的printf()將始終以它的參數從棧中,因爲它是一個變量參數列表的功能。或者是否有人知道任何其他調用約定功能如printf()?此外,我假設沒有必要在堆棧上放置其他任何東西,因爲沒有其他變量。所以這個錯誤的電話printf將打印什麼在main()的堆棧頂部。但是,在我的假設不成立的情況下,可能還有其他體系結構和調用約定。

+3

鑑於printf是一個庫函數,我無法看到編譯器如何能夠選擇將參數傳遞給它的方式。當編譯庫並且編譯器必須符合時才選擇調用約定。 – torak 2010-10-01 14:42:39

+0

優化不在_printf()_的調用中,而是存儲_main()_中的局部變量。有問題的調用_printf()_只是揭示棧上的內容。 – Codo 2010-10-02 15:32:00

4

這是未定義的行爲。

使用優化編譯器時,這3個值可能會因未使用而優化。它會打印垃圾。

0

在MingW-GCC中:3個垃圾值。

在VC++ 2010中:0,0和一個垃圾值。

2

如果格式的參數不足,則行爲未定義。

3

行爲是未定義的,這意味着編譯器可以自由處理它認爲合適的任何方式。就語言標準而言,Turbo C和gcc都在做「正確」的事情。

+3

而編寫代碼的程序員並不是「正在做」正確的「事情」! – 2010-10-01 15:08:27

1

你的老師是錯的,但並不完全。

函數中聲明的變量默認爲auto而不是static

int foo(void) { 
    static int x; 
    int y; 
    auto int z; 

    /* ...other code... */ 
} 

這意味着,在上述y功能是自動的,就像Z,即使auto關鍵字未在其聲明中使用。順便說一下,關鍵字auto幾乎從不使用。許多C(和C衍生語言)程序員甚至不知道auto是一個關鍵字,因爲它很少被使用。

作爲auto變量通常意味着該變量存儲在程序的系統堆棧或寄存器中或其中的某些組合中。它可以在函數執行期間的不同時間處於不同的位置,並且在調用另一個函數時,寄存器中的局部變量通常會被推送到堆棧。一些局部變量甚至可能被優化掉,這意味着在某些時候,編譯器能夠確定特定變量的未來值不再需要用於滿足未來代碼的輸入需求(或者變量不會改變,其值只是在指令內編碼)。在優化的代碼上使用調試器會很複雜。

當你得到一個局部變量的地址時,編譯器會嘗試將其鎖定到一個特定的地址(可能通過將其存儲在堆棧中)。

當大多數編譯器查看您的代碼時,他們將會看到這些局部變量的名稱在聲明後不再使用,並且可能決定不在任何位置存儲它們的值。即使它將這些值存儲在堆棧中,它也可能在設置調用printf之前將其他值推入堆棧。就像編譯器不必保留你命名的變量一樣,它也可以自由創建它自己的臨時變量。