2014-04-25 101 views
6

我想了解C中的堆棧幀,因此我編寫了一個簡單的C代碼來分析堆棧幀。瞭解堆棧幀C

  • 首先在FUN1的()返回一個被初始化爲10到PTR這導致了警告,但沒關係......如果我現在打印* PTR的值,它打印的局部變量的地址10,即使這沒關係...

  • 接下來fun2()返回一個局部變量的地址,它甚至沒有被初始化,如果我嘗試打印* ptr的值,現在它打印10,無論我是否返回a或b的地址...

  • 要理解這裏實際發生的事情,我使用了gdb。用gdb ,我開始一步一步的調試,當我到達行「回&一個」在FUN2(),我試圖打印B的地址,打印& b但它印 無法採取不是左值的「b」的地址。

,當我嘗試打印的地址我不明白,打印&一個它打印精美絕倫,那麼爲什麼不解決B的。 * a爲什麼不是一個左值?

# include <stdio.h> 

int * fun1() { 
    int a = 10; 
    return &a; 
} 

int * fun2() 
{ 
    int a; 
    int b; 
    return &a;   // return &b; 
} 

int main() 
{ 
    int *ptr; 
    ptr = fun1(); 
    ptr = fun2(); 
    printf ("*ptr = %d, fun2() called...\n", *ptr); 
    return 0; 
} 
+0

http://stackoverflow.com/a/18479996/1814023 –

+1

你調用未定義的行爲。不能保證結果會有任何意義或做到您期望的堆棧佈局。標準的誇張之處在於,該程序允許[惡魔](http://www.catb.org/jargon/html/N/nasal-demons.html)飛出你的鼻子。 – user2357112

+2

很幸運,打印'* ptr'打印10;它肯定不能保證這麼做(你正在調用未定義的行爲)。但你真的應該顯示所有的代碼。在代碼中,編譯器可能會將'b'作爲一個未使用的變量,因此它沒有位置,因此您無法獲取它的地址。以某種方式在代碼中使用'b',你就可以打印出來。請不要報告「類似的東西」;確切地說,並且準確地報告調試器說的內容。 –

回答

3

編譯器正在優化掉fun2中的一些代碼。

如果您返回&a,它將優化爲int b;。如果您返回&b,它將優化離開int a;。如果您添加一些虛擬計算,您將看到返回值的地址將會不同。

int * fun2() 
{ 
    int a; 
    int b; 
    int* p = &a; 
    p = &b; 
    return p; 
} 

變化main打印的fun1fun2返回值。

int main() 
{ 
    int *ptr; 
    ptr = fun1(); 
    printf ("ptr = %p, fun1() called...\n", ptr); 
    ptr = fun2(); 
    printf ("ptr = %p, fun2() called...\n", ptr); 
    printf ("*ptr = %d, fun2() called...\n", *ptr); 
    return 0; 
} 

當我運行這段代碼,我得到下面的示例輸出:

 
ptr = 0x7ffff98c70ec, fun1() called... 
ptr = 0x7ffff98c70e4, fun2() called... 
*ptr = 32749, fun2() called... 
+0

雅這就是如果我初始化b,則返回true,如果我使用-O0優化級別進行編譯,則返回垃圾,但同樣如此。但是,當我用-O0優化級別進行編譯時,結果再次相同,即10 – Adarsh

0

它返回到B的地址時,編譯對我就好了。但是你不應該返回一個局部變量的地址。 Check out this link

+0

雅這是真的,但我的目標是不從這個代碼完成任何事情,但瞭解如何在一個函數中使用堆棧變量的地址可以在另一個函數中重新使用...感謝您的幫助... – Adarsh