寫生活日誌麼?想都別想:)
這件事跟未初始化的非靜態局部變量的值有關。
通常,作爲一個合格的程序員,定義變量都會給它初始化,特別是非靜態的局部變量,使用未初始化的非靜態局部變量會發生錯誤。然而,喵哥今天在看書的時候遇到這麼一個奇葩的例子:
#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沒啥關係了。。。