在C語言中,有多少個未初始化的局部變量?答案通常是:與編譯器有關。
可以但不保證初始化為0。
不確定。
簡而言之,它們都是嚴肅的形而上學的答案,這很煩人。
但是,當有人為您談論編譯器,C庫和處理器體系結構時,卻無法為您提供重現該問題的真實場景,那么這個人很可能是胡說八道。
實際上,這個問題本身是一個錯誤的問題。
如果您能說100,000個單詞,我們只需要能夠確定其在特定情況下的特定行為。
當然,這需要設計一個相對可行的實驗。
在演示實際代碼的行為之前,讓我給出一些知識。
CPU無法識別變量,更不用說變量名了。
CPU只會從特定的存儲位置獲取值,或者將值存儲在特定的存儲位置,因此當被問到變量的值是什么時,有必要知道該變量的值存儲在哪里。
考慮以下代碼:#include void func1(){int a; printf(“ func1:%d ”,a); a = 12345;} void func2(){int b; printf(“ func2:%d ”,b);} void func4(){int d; printf(“ func3:%d ”,d);} void func3(){int c; printf(“ func3:%d " c); c = 54321; func4();} void test_call(){func3();} int main(int argc,char ** argv){func1(); func2(); test_call();}我們從func1到func4一共有4個函數,并且內部有一個未初始化的局部變量。
它們的價值是什么?對于這種局部變量,其值取決于:變量在堆棧中的位置。
該變量對應于堆棧位置是否已存儲過?如您所見,上面的第一點標記了一個內存位置,第二點是代碼的行為,即只要有存儲對應位置的代碼,以及后面的代碼(如果沒有復位值)位置的位置,位置將在存儲后保留原始值。
驗證非常簡單,請嘗試:[root @ localhost test]#./a.outfunc1:0func2:12345func3:0func3:0根據函數調用堆棧框架,func1的局部變量a和局部變量的變化而定func2的變量b顯然位于同一位置。
調用func1時,這是一個新的內存(也許在進入main之后,堆棧幀到達了該位置之后),a的值取決于在此位置被調用到內存中的頁面的相應偏移量的初始值。
在操作系統(tǒng)上:將操作系統(tǒng)分配給程序頁面時,操作系統(tǒng)可能會將頁面清除為零頁面。
堆棧分配不會涉及C庫。
顯然,這里不涉及C庫的行為,但是malloc分配的內存涉及C庫。
打印的結果顯示a的值為0,我們認為操作系統(tǒng)已向應用程序返回了零頁。
接下來,該函數將其分配給func1中的12345后返回。
當下一次調用func2時,將在以前退出func1的堆棧框架位置重建堆棧框架,并且相應位置仍為12345。
在執(zhí)行func1代碼指令0的ret操作后,我沒有看到堆棧清除。
考慮因素,不應有此類說明。
查看test_call函數,很明顯,func3和func4不是使用同一堆棧幀來調用的,因此即使將func3中的c分配給了54321,也不會影響func4在堆棧幀上方的值d 。
因此,c和d的初始值保持為0.然后,在指令級初始化局部變量而不初始化局部變量的區(qū)別是什么?這很簡單,只需用自己的眼睛看一下即可。
首先看一下未初始化的局部變量的func1:// int a; 00000000004005ad:4005ad:55 push%rbp 4005ae:48 89 e5 mov%rsp,%rbp 4005b1:48 83 ec 10 sub $ 0 x10,%rsp 4005b5:8b 45 fc mov -0x4(%rbp),%eax 4005b8:89 c6 mov%eax,%esi 4005ba:bf 90 07 40 00 mov $ 0x400790,%edi 4005bf:b8 00 00 00 00 mov $ 0x0,%eax 4005c4: e8 b7 fe ff ff callq 400480 4005c9:c7 45 fc 39 30 00 00 movl $ 0x3039,-0x4(%rbp)4005d0:c9 Leaveq 4005d1:c3 retq查看局部變量a的初始化2222版本:// int a = 2222; 00000000004005ad:4005ad:55 push%rbp 4005ae:48 89 e5 mov%rsp,%rbp 4005b1:48 83 ec 10 sub $ 0x10,%rsp 4005b5:c7 45 fc 00 00 00 00 movl $ 0x0,-0x4( %rbp)4005bc:8b 45 fc mov -0x4(%rbp),%eax 4005bf:89 c6 mov%eax,%esi 4005c1:bf 90 07 40 00 mov $ 0x400790,%edi 4005c6:b8 00 00 00 00 mov $ 0 x0,%eax 4005cb:e8 b0 fe ff ff callq 400480 4005d0:c7 45 fc 39 30 00 00 movl $ 0x3039,-0x 4(%rbp)4005d7:c9 Leaveq 4005d8:c3 retq僅缺少一條指令:4005b5: c7 45 fc 00 00 00 00 movl $ 0x0,-0x4(%rbp)初始化操作由實際指令完成