[英]When are local variables initialized in C?
考慮下面的例子
void func(int i){
if(i) {
int arr[2048] = {0};
//Doing something related to arr;
} else {
//Doing something
}
}
我在if
塊中有一個大型數組聲明。 這個數組的初始化應該花費一些時間。 我的問題是:如果i == 0
,這個數組會被初始化嗎?
如果i == 0,這個數組會被初始化嗎?
因為你的代碼是
if(i) { int arr[2048] = {0}; //Doing something related to arr; } else { //Doing something }
如果i==0
則該數組不存在,因此無法初始化,該數組僅存在於if的分支中i != 0
要理解編譯器行為,您應該考慮在C語言中,每個變量都有一個存儲類 ( ISO / IEC 9899:201x§6.2.4對象的存儲持續時間 ),它表征了它的行為及其“ 生命 ”,這意味着存在這樣的對象(變量是一個對象),以及它的合法訪問條件。 存儲類是4:靜態,線程,自動和分配。 后者使用動態內存分配。
在您的情況下,數組arr[2048]
是一個自動對象,其生命周期定義(在標准@ point 6的同一段中):
對於沒有可變長度數組類型的此類對象,其生命周期從entry進入與其關聯的塊,直到該塊的執行以任何方式結束。 (輸入一個封閉的塊或調用一個函數暫停,但不會結束,執行當前塊。)
如果以遞歸方式輸入塊,則每次都會創建該對象的新實例。
對象的初始值是不確定的 。
如果為對象指定了初始化,則每次在執行塊時達到聲明或復合文字時都會執行初始化 ; 否則,每次達到聲明時,該值將變為不確定。
這解釋了:
第一點很清楚,已經是你問題的答案了。 您引用的代碼是:
{ //Block init
int arr[2048] = {0};
//Doing something related to arr;
} // block end
如果不輸入塊,則對象的生命周期 (數組)不會開始:數組不存在。 當然,在這種情況下,不能對對象執行任何操作,甚至是初始化。
現在, 第2點有助於更好地澄清。 表達方式:
int arr[2048] = {0};
由於數組對象的存儲類, 編譯器在功能上不會將其解釋為具有對象初始化的聲明 。 它實質上被視為聲明和轉讓 。
有什么不同?
具有與自動不同的存儲類的初始化變量的聲明是通過對用戶代碼透明的機制實現的,在BSS部分中靜態分配值或者使用屬於編譯器序言和結尾的代碼, 即使對象不是 ,也可能發生這種情況。訪問 。
在另一種情況下,初始化代碼(賦值) 是用戶代碼的一部分,因此在執行流邏輯之后執行 。
這是官方行為。 在引擎蓋下檢查你可以看到,在某些情況下,自動變量的空間恰好從對象生命開始分配,但這些行為嚴格依賴於CPU架構,並且基本上在發生時不會產生功能差異代碼是語言標准(這是兼容編譯器的基本屬性 )。
實際上,變量將在使用前初始化,無論它是否放在內部范圍內。 這段代碼:
void func1 (int i){
if(i) {
int arr[2048] = {0};
printf("%d", arr[666]);
} else {
//Doing something
}
}
提供與此代碼完全相同的機器代碼:
void func2 (int i){
int arr[2048] = {0};
if(i) {
printf("%d", arr[666]);
} else {
//Doing something
}
}
x86上的gcc -O3給出:
.LC0:
.string "%d"
func1:
test edi, edi
jne .L4
ret
.L4:
xor esi, esi
mov edi, OFFSET FLAT:.LC0
xor eax, eax
jmp printf
和
.LC0:
.string "%d"
func2:
test edi, edi
jne .L7
ret
.L7:
xor esi, esi
mov edi, OFFSET FLAT:.LC0
xor eax, eax
jmp printf
如你所見,它們是相同的。
盡管如此,盡可能地限制變量的范圍是一種很好的設計實踐,但這與性能無關。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.