簡體   English   中英

為什么C中的靜態初始化表達式不能使用常量數組的元素?

[英]Why can't a static initialization expression in C use an element of a constant array?

以下(公認的做作)C程序無法編譯:

int main() {
const int array[] = {1,2,3};
static int x = array[1];
}

使用gcc(或Microsoft的CL.EXE)編譯上述C源文件時,出現以下錯誤:

error: initializer element is not constant
static int x = array[1];
               ^

這種簡單直觀的語法肯定是有用的,所以這似乎應該是合法的,但顯然它不是。 當然,我不是唯一一個對這種明顯愚蠢的限制感到沮喪的人。 我不明白為什么這是不允許的 - 通過使這個有用的語法非法,C語言試圖避免什么問題?

看起來它可能與編譯器為初始化生成匯編代碼的方式有關,因為如果刪除“static”關鍵字(使得變量“x”在堆棧上),那么它編譯得很好。

然而,另一個奇怪的事情是它在C ++中編譯得很好(即使使用static關鍵字),但在C中也沒有。因此,C ++編譯器似乎能夠生成必要的匯編代碼來執行這樣的初始化。

編輯:相信戴維斯 - 為了安撫SO權力 - 我會尋求以下類型的事實信息來回答這個問題:

  1. 是否有支持這些語義的遺留代碼會破壞?

  2. 這些語義是否已經正式提交給標准委員會?

  3. 有沒有人有理由拒絕這些語義的允許?

具有靜態存儲持續時間的對象(讀取:在文件范圍或使用static關鍵字聲明的變量)必須由編譯時常量初始化。

關於初始化狀態的C標准第6.7.9節:

4具有靜態或線程存儲持續時間的對象的初始值設定項中的所有表達式應為常量表達式或字符串文字。

關於常量表達式的6.6節說明:

7初始值設定項中的常量表達式允許更多的緯度。 這樣的常量表達式應為或評估為以下之一:

  • 算術常量表達式,
  • 空指針常量,
  • 地址常數,或
  • 完整對象類型的地址常量加上或減去整數常量表達式。

8算術常量表達式應具有算術類型,並且只能具有整數常量,浮點常量,枚舉常量,字符常量,結果為整數常量的sizeof表達式和_Alignof表達式的操作數。 算術常量表達式中的轉換運算符只能將算術類型轉換為算術類型,除非作為sizeof或_Alignof運算符的操作數的一部分。

9地址常量是空指針,指向左值的指針,指定靜態存儲持續時間的對象,或指向函數指示符的指針; 它應該使用一元&運算符或一個轉換為指針類型的整數常量顯式創建,或者通過使用數組或函數類型的表達式隱式創建。 array-subscript []和member-access。 和 - >運算符,地址&和間接*一元運算符和指針強制轉換可用於創建地址常量,但不能使用這些運算符訪問對象的值。

通過上面的定義, const變量不符合常量表達式,因此不能用於初始化static對象。 C ++對其他有沒有const變量作為真正的常數,從而使他們能夠初始化靜態對象。

如果C標准允許這樣做,那么編譯器必須知道數組中的內容。 也就是說,編譯器必須具有數組內容的編譯時模型。 如果沒有這個,編譯器需要為每個數組做一些工作:它需要知道它的名稱和類型(包括它的大小),以及一些其他細節,例如它的鏈接和存儲持續時間。 但是,如果在代碼中指定了數組的初始化,編譯器就可以將相關信息寫入它正在增長的目標文件中,然后忘記它。

如果編譯器必須能夠在編譯時從數組中獲取值,則必須記住該數據。 由於數組可能非常大,這給委員會可能不希望的C編譯器帶來了負擔,因為C旨在在各種環境中運行,包括那些資源有限的環境。

C ++委員會做出了不同的決定,C ++的翻譯更加繁瑣。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM