[英]Why does printf print 0s when I wrongly returned pointer to value on the stack only when optimizing with gcc compiler?
我試圖了解此示例中 printf 的行為。 當然,這里的主要問題是我們正在返回一個指向堆棧上的值的指針,該值在 function Boo 返回后彈出。
我用 gcc 編譯。 在 test1 中:我得到了 7 打印兩次,這是預期的。 以及 test2 中第二個 printf 上的垃圾值。 但是當我用 gcc -O3 編譯時,我在兩種情況下都打印了 0並且編譯器警告關於返回局部變量的地址。
test.c: In function 'Foo': test.c:8:12: warning: function returns address of local variable [-Wreturn-local-addr] return t; ^ test.c:5:9: 注意:此處聲明為 int j;
有人可以幫我解釋導致這種行為的 printf 的行為如何嗎?
int *Boo(int i, int *p)
{
int j;
int *t = &j;
*t = i + *p;
return t;
}
void Foo(int x)
{
if (x == 0) { return;}
Foo(x - 1);
}
//test1
int main(void)
{
int x = 5;
int *t = Boo(2, &x);
printf("%d", *t);
printf("%d", *t);
return 0;
}
//test2
int main(void)
{
int x = 5;
int *t = Boo(2, &x);
printf("%d", *t);
Foo(8);
printf("%d", *t);
return 0;
}
GCC 看到Boo
返回一個指向局部變量的指針,因此任何使用該指針的嘗試都是未定義的行為。 這意味着,根據 C 標准,編譯器可以為所欲為,在這種情況下,GCC 通常會生成“高效”的代碼,即使它與程序員的意圖完全無關。 它內聯了對Boo
的調用,它沒有可見的效果,因此被優化掉了,它選擇了一種“有效”的方式來為printf
提供一個參數,它恰好是常數 0。
參見神螺栓。 printf 的printf
參數進入esi
,它來自ebp
,它被歸零。 我想有一個錯過的優化,因為它在調用printf
以重新加載到esi
時將相同的 0 保存在ebp
中,而不是之后重新歸零esi
。 但整個分析有點毫無意義,因為行為是未定義的。
Boo
本身被優化為 function ,它只返回一個NULL
指針並且不執行任何其他操作,由於未定義的行為,這再次是合法的,但該版本的Boo
不被程序調用。 Foo
也被優化為 function 立即返回而不遞歸; 編譯器可以判斷遞歸調用無效。 (如果將否定參數傳遞給Foo
,由於簽名的 integer 溢出,您將有未定義的行為,因此編譯器不需要處理這種情況。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.