記一件有意思的事

寫生活日誌麼?想都別想:)

這件事跟未初始化的非靜態局部變量的值有關。

通常,作爲一個合格的程序員,定義變量都會給它初始化,特別是非靜態的局部變量,使用未初始化的非靜態局部變量會發生錯誤。然而,喵哥今天在看書的時候遇到這麼一個奇葩的例子:

#include <bits/stdc++.h>
using namespace std;

int global_init_var = 0;
__attribute__((section("foo")))  int global_uninit_var;

void func1(int i){
    printf("%d\n", i);
}

int main(){
    static int static_var = 85;
    static int static_var2;
    int a = 1;
    int b;    //沒有初始化
    func1(static_var + static_var2 + a +b);
    return 0;
}

看到這代碼第一反應就是這代碼是不是錯了,然後喵哥本着“實踐是檢驗真理的唯一標準”的精神,把上面的代碼碼了下來,然後跑了一下

我驚了,居然順利運行過了。本以爲由於b沒有初始化而得到一個非法的值,但是用GCC跑出來的b老老實實的默認爲0

有點顛覆三觀了,跟平時完全不是一回事,然後想到這會不會跟用的編譯器有關,我這裏用的是GCC。特意去windows用VS跑了一遍,幸好出錯了

這是在debug的模式下跑的,b被賦值爲0xcccc cccc,併發生異常中斷。

如果是release下跑,則不會報異常中斷,但是運行結果是錯的。

這說明需要要對非靜態局部變量初始化不是錯覺,平常也需要這麼做。

並且,用clang編譯得到的結果也是不對的:

那麼爲什麼GCC會給它賦值爲0呢,這大概就是底層編譯器底層實現的區別了,在網上看到這麼一段話:


引自百度知道:gcc局部變量不用初始化麼
以 C99 標準爲例:

6.7.8/10 未顯式初始化的非靜態局部變量的值是「不定的」。

3.17.2 「不定的值」是「未指定的值」或「陷阱標識」。

3.17.3 「未指定的值」是該類型有效值,但本國際標準對於具體選擇哪個值不作要求。

6.2.6.1/5 對值爲「陷阱標識」的對象進行讀操作是未定義行爲。

所以,這種代碼有可能觸發未定義行爲,能不能跑全靠運氣。即便不觸發,取值是多少也沒有標準保障。


GCC應該是默認把爲初始化的整數值初始化爲0吧,在喵哥看的那本書中也的確經常提到未初始化與初始化爲0 的隱晦關係。比如:

經過初始化的全局變量和靜態局部變量會保存在.data處,對於沒有初始化的全局變量和靜態局部變量則會保存在.bss處,但是如果全局變量和靜態局部變量初始化爲0的話,則這些全局變量和靜態局部變量也會保存在.bss處。

這麼說來GCC中對於這個“不定值”的定義可能就是0吧。


2019.07.20

用clang編譯的沒有初始化的全局變量和靜態局部變量和初始化爲0的全局變量和靜態局部變量也保存在.bss處,所以這個關係跟非靜態局部變量初始化爲0沒啥關係了。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章