2011-11-27 62 views
20

在C中,初始化一個變量到它自己的值是否合理?如果是的話,爲了什麼?初始化一個變量到它自己的未定義值

請允許我詳細說明。在Git源文件中,有一些將變量初始化爲自己的未定義值的示例,如transport.cwt-status.c中所示。我從這些聲明中刪除了任務並運行測試。看到沒有迴歸,我認爲這些任務是多餘的。

另一方面,我用GCC 4.6和Clang 2.9做了一些簡單的測試。

#include <stdio.h> 
int main() { 
    printf("print to increase probability of registers being non-zero\n"); 
    int status = status; 
    return printf("%i\n", status); 
} 

-Wall -std=c99和各種-O水平打印編譯沒有警告,並表明status == 0。具有非零優化級別的Clang雖然會打印一些垃圾值。這讓我推斷這些表達式的結果是不確定的。

我可以想象,這樣的賦值可以抑制未初始化的變量警告,但從Git獲取的示例並非如此。刪除作業不會引入任何警告。

這樣的任務是一個未定義的行爲?如果不是,你用它們做什麼?


我建議在Git郵件列表上進行更改。 Here's what I've learned

+0

也許git中的例子不會爲* your *系統禁止未初始化的變量警告,而是在其他開發人員經常使用的系統上禁止該警告。使用GCC,未初始化的變量警告受優化標誌影響,並且Clang生成一組完全不同的警告,即使它是GCC的「插入式替代品」。 –

+1

我會初始化這些變量爲0(或-1),而不是完全放棄初始化。有人爲了某個目的添加了代碼;即使我發現使用奇怪的機制,我也可以尊重目的。 –

+1

@JonathanLeffler,不僅奇怪,在陷阱表示的平臺上會產生未定義的行爲。 –

回答

11

這將編譯,因爲標準C99§6.2.1/ 7說:

任何標識符不是結構,聯合或枚舉標記「具有範圍,只是在其聲明完成後開始「。聲明符後面跟着初始值設定項。

然而,status值是不定。你不能依賴它被初始化爲有意義的東西。

它是如何工作的?
int status爲堆棧中存在的變量創建一個空間(本地存儲),然後進一步讀取該空間以執行status = statusstatus可能會初始化爲存在於堆棧幀中的任何值。

如何防範這種自我初始化?
GCC提供特定設置來檢測自己的初始化,並報告爲錯誤:

-Werror =未初始化-Winit自

爲什麼在此代碼中使用?
我能想到它是在該程序代碼中使用的唯一原因是爲了抑制未使用變量警告爲前:在transport.c,如果控制從來沒有while循環中去,然後在控制流動cmp將未使用的和編譯器必須爲其生成警告。同樣的場景似乎是在wt-status.c

+2

我認爲這個想法並不是要壓制'未使用的變量'警告(你可以通過刪除未使用的變量來做到這一點),而是'(有時)在初始化之前使用'警告。這是一個小細節 - 它不會改變答案主要部分的有效性。 –

+0

@JonathanLeffler:你的評論很有用。我在回答中弄錯了這一點。 –

1

對我來說,這種自分配初始化的唯一原因是爲了避免警告。

對於你的transport.c,我甚至不明白它爲什麼有用。我會留下cmp未初始化。

我自己的習慣(至少在C中)是初始化所有變量,通常爲0.編譯器將優化不需要的初始化,並且初始化所有變量使調試更容易。

存在這樣的情況,當我想一個變量保持未初始化,而我可能會自己分配它:隨機種子:

unsigned myseed = myseed; 
srand(myseed); 
+0

但是有沒有任何運行時分析工具可以注意到,當它仍然保存未初始化的字節時,會讀取「cmp」?邏輯應該在'while'中讀入'if'前強制'cmp'分配一些東西,所以你希望編譯器「閉嘴,因爲人知道他在做什麼」,但是'int cmp = 0'會擊敗運行時分析並可能隱藏錯誤。 –

+0

你的意思是*編譯時*不*運行時*分析?但我不明白你的意見。 –

+0

'int cmp = cmp'可能足以欺騙編譯器認爲'cmp'總是在讀取之前被分配,所以編譯時警告將被抑制。但是,如果你在運行時觀察字節,那麼'int cmp = cmp'仍然會讓'cmp'滿了垃圾,直到'while'循環的條件初始化爲止。所以,如果邏輯有缺陷,'if'可以讀取'cmp'而不用'while'分配一個值,那麼當使用'int cmp = cmp'時可以檢測到這個值。使用'int cmp = 0'會抑制兩種可能的警告。 –

1

在MacOS X 10.7.2,我試過了這個例子 - 與結果顯示...

$ cat x3.c 
#include <stdio.h> 

int status = -7; 

int main() 
{ 
    printf("status = %d\n", status); 
    int status = status; 
    printf("status = %d\n", status); 
    return 0; 
} 
$ make x3 
gcc -O -std=c99 -Wall -Wextra x3.c -o x3 
$ ./x3 
status = -7 
status = 1787486824 
$ 

其中main()當地status已使用printf()所以自初始化拷貝垃圾各地的棧空間。

0

status可變我覺得status = status不會改變的status值(比int status;)。我認爲這是用來抑制unused variable的警告。