亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解C語言未初始化的局部變量是多少

 更新時間:2020年07月19日 10:44:27   作者:dog250  
這篇文章主要給大家介紹了關(guān)于C語言未初始化的局部變量是多少,文中通過示例代碼以及圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧

C語言中,未初始化的局部變量到底是多少?

答案往往是:

  • 與編譯器有關(guān)。
  • 可能但不保證初始化為0。
  • 未確定。

總之,全部都是些一本正經(jīng)的形而上答案,這很令人討厭。

但凡一些人給你滔滔不絕地扯編譯器,C庫,處理器體系結(jié)構(gòu)卻給不出一個實際場景復(fù)現(xiàn)問題的時候,這人大概率在扯淡。

又是周五回家時,大巴車上作短文一篇。

其實,這個問題本身就是錯誤的問法,說全了能講10萬字,我們只要能在特定場景下確定其特定行為就OK了,當(dāng)然,這就需要設(shè)計一個比較OK的實驗。

在演示一個實際代碼行為之前,先給出一個知識, CPU不認(rèn)識變量,更無法識別變量的名字,CPU只會從特定的內(nèi)存位置取值或者將值存到特定的內(nèi)存位置,因此當(dāng)問一個變量的值是多少的時候,必須要知道這個變量對應(yīng)的值被保存在什么地方。

來看下面的代碼:

#include <stdio.h>

void func1()
{
 int a;
 printf("func1:%d\n", a);
 a = 12345;
}

void func2()
{
 int b;
 printf("func2:%d\n", b);
}

void func4()
{
 int d;
 printf("func3:%d\n", d);
}

void func3()
{
 int c;
 printf("func3:%d\n", c);
 c = 54321;
 func4();
}

void test_call()
{
 func3();
}

int main(int argc, char **argv)
{
 func1();
 func2();

 test_call();
}

我們有func1~func4一共4個函數(shù),其內(nèi)部均有一個未初始化的局部變量,它們的值到底是多少呢?

對于這種局部變量,它們的值取決于:

  • 變量在棧中的位置。
  • 變量對應(yīng)的棧位置在 之前 有沒有被store過。

可以看到,上述第一點標(biāo)記了一個內(nèi)存位置,第二點則是代碼的行為,也就是說,只要有代碼去store對應(yīng)的位置, 且后續(xù)的代碼沒有reset該位置的值的話,該位置就會保留著原先被store后的值。

驗證非常簡單,試一下就知道了:

[root@localhost test]# ./a.out
func1:0
func2:12345
func3:0
func3:0

按照函數(shù)調(diào)用棧幀的變化,func1的局部變量a和func2的局部變量b顯然是位于同一個位置的,在func1被調(diào)用時,這是一塊新的內(nèi)存(可能在進(jìn)入main之前有棧幀到達(dá)過這個位置),a的值取決于調(diào)入內(nèi)存該位置的頁面對應(yīng)偏移的初始值,這取決于操作系統(tǒng):

操作系統(tǒng)在分配給程序頁面時可能會將頁面clear為零頁。

棧的分配不會涉及C庫,這里顯然并不涉及C庫的行為,但類似malloc分配的內(nèi)存則涉及C庫了。

打印結(jié)果,a的值為0,我們認(rèn)為操作系統(tǒng)返回給了應(yīng)用程序零頁。接下來在func1中將其賦值12345之后函數(shù)返回,接下來調(diào)用func2的時候,在之前func1已經(jīng)退出的棧幀位置重建棧幀,對應(yīng)位置依然還是12345。

我沒有看到func1的ret操作后面有stack清0的代碼指令。效率考慮,也不該有這樣的指令。

再看test_call函數(shù),很明顯,func3和func4調(diào)用使用的并不是同一個棧幀,因此即便是在func3中對c賦值了54321,也不會影響在其棧幀之上的func4的棧幀對應(yīng)位置的值d。因此c和d的初始值均保持為0。

那么,初始化一個局部變量和不初始化一個局部變量,在指令層面上,區(qū)別在哪里呢?

很簡單,親眼看一下就知道,先看未初始化局部變量的func1:

// int a;
00000000004005ad <func1>:
 4005ad: 55      push %rbp
 4005ae: 48 89 e5    mov %rsp,%rbp
 4005b1: 48 83 ec 10    sub $0x10,%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 <printf@plt>
 4005c9: c7 45 fc 39 30 00 00 movl $0x3039,-0x4(%rbp)
 4005d0: c9      leaveq
 4005d1: c3      retq

再看初始化局部變量a為2222的版本:

// int a = 2222;
00000000004005ad <func1>:
 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 $0x0,%eax
 4005cb: e8 b0 fe ff ff   callq 400480 <printf@plt>
 4005d0: c7 45 fc 39 30 00 00 movl $0x3039,-0x4(%rbp)
 4005d7: c9      leaveq
 4005d8: c3      retq

僅僅差了一條指令:

 4005b5: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)

初始化的操作是依靠實實在在的指令完成的。

總結(jié)一句, 函數(shù)返回在pop出當(dāng)前棧幀的時候,并不會清理它遺留在棧幀里的數(shù)據(jù),下個函數(shù)調(diào)用再次重用到該棧幀的內(nèi)存時,未初始化的局部變量將會被遺留數(shù)據(jù)影響,從而變得不確定!

所以,記得初始化你的局部變量。如果你不這樣做,上帝終究會將你經(jīng)理了的。

總結(jié)

到此這篇關(guān)于詳解C語言未初始化的局部變量是多少的文章就介紹到這了,更多相關(guān)C語言未初始化的局部變量內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • c++ lambda捕獲this 導(dǎo)致多線程下類釋放后還在使用的錯誤問題

    c++ lambda捕獲this 導(dǎo)致多線程下類釋放后還在使用的錯誤問題

    Lambda表達(dá)式是現(xiàn)代C++的一個語法糖,挺好用的。但是如果使用不當(dāng),會導(dǎo)致內(nèi)存泄露或潛在的崩潰問題,這里總結(jié)下c++ lambda捕獲this 導(dǎo)致多線程下類釋放后還在使用的錯誤問題,感興趣的朋友一起看看吧
    2023-02-02
  • C/C++可變參數(shù)函數(shù)的實現(xiàn)

    C/C++可變參數(shù)函數(shù)的實現(xiàn)

    這篇文章主要介紹了C/C++可變參數(shù)函數(shù)的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • 利用C語言來求最大連續(xù)子序列乘積的方法

    利用C語言來求最大連續(xù)子序列乘積的方法

    這篇文章主要介紹了利用C語言來求最大連續(xù)子序列乘積的方法,基本的思路以外文中還附有相關(guān)ACM題目,需要的朋友可以參考下
    2015-08-08
  • 如何尋找數(shù)組中的第二大數(shù)

    如何尋找數(shù)組中的第二大數(shù)

    本篇文章是對如何尋找數(shù)組中的第二大數(shù)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C++內(nèi)存對象布局小測試

    C++內(nèi)存對象布局小測試

    這篇文章主要介紹了C++內(nèi)存對象布局小測試,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • C/C++ MD5算法的實現(xiàn)代碼

    C/C++ MD5算法的實現(xiàn)代碼

    下面就將網(wǎng)上有關(guān)MD5算法一些知識整理一下,方面自己查閱,需要的朋友可以參考下
    2017-07-07
  • C語言直接插入排序算法介紹及示例

    C語言直接插入排序算法介紹及示例

    插入排序是把一個記錄插入到已排序的有序序列中,使整個序列在插入該記錄后仍然有序。插入排序中較簡單的種方法是直接插入排序,其插入位置的確定方法是將待插入的記錄與有序區(qū)中的各記錄自右向左依次比較其關(guān)鍵字值的大小
    2022-08-08
  • 算法詳解之分支限界法的具體實現(xiàn)

    算法詳解之分支限界法的具體實現(xiàn)

    這篇文章主要介紹了算法詳解之分支限界法的具體實現(xiàn),需要的朋友可以參考下
    2014-02-02
  • C++ 純虛函數(shù)詳解

    C++ 純虛函數(shù)詳解

    本文主要介紹了C++ 純虛函數(shù)詳解,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • 詳解c++中的 static 關(guān)鍵字及作用

    詳解c++中的 static 關(guān)鍵字及作用

    這篇文章主要介紹了c++中的 static 關(guān)鍵字,在我們?nèi)粘J褂眠^程中,static通常有兩個作用,具體內(nèi)容在文中給大家詳細(xì)介紹,需要的朋友可以參考下
    2020-02-02

最新評論