2012-10-19 22 views
13

標準似乎暗示有上的變量的定義的數量沒有限制,如果它不是ODR使用的(§3.2/ 3):如果我不使用變量,我可以在翻譯單元中有多個定義嗎?

每個程序應包含正好一個定義每個非內聯函數或在該程序中使用的變量;不需要診斷。

它說,任何變量不能一個翻譯單元(§3.2/ 1)內定義多次:

未翻譯單元應包含任何變量的多個定義,功能,類類型,枚舉類型或模板。

但我無法在整個程序中找到對非odr使用變量的限制。那麼,爲什麼我不能編譯類似如下:

// other.cpp 
int x; 

// main.cpp 
int x; 
int main() {} 

編譯和鏈接這些文件與G ++ 4.6.3,我得到一個鏈接錯誤multiple definition of 'x'。說實話,我期望這一點,但由於x沒有任何地方使用臭氧(據我所知),我看不出標準如何限制這一點。或者它是不確定的行爲?

回答

11

您的程序違反了連接規則。 C++ 11§3.5[基本。鏈接]/9狀態:

兩個名字是相同的,在不同的範圍應當是指同一 變量,函數,類型,枚舉,模板或命名空間中聲明,如果

  • 兩個名稱具有外部鏈接,或者兩個名稱都有內部鏈接並在同一個翻譯單元中聲明;和

  • 這兩個名稱是指同一名稱空間的成員或成員,而不是繼承,同一類;和

  • 當兩個名稱都表示函數時,函數的參數類型列表是相同的;和

  • 當兩個名稱都表示功能模板時,簽名是相同的。

(我引用了完整的段落,以供參考。第二兩顆子彈不適用於此。)

在你的程序中,有兩個名字x,這都是一樣的。它們在不同的範圍內聲明(在這種情況下,它們在不同的翻譯單元中聲明)。兩個名稱都具有外部鏈接,並且這兩個名稱都指向同一名稱空間(全局名稱空間)的成員。

這兩個名字不是表示相同的變量。聲明int x;定義了一個變量。由於程序中有兩個這樣的定義,程序中有兩個變量。一個翻譯單元中的名稱「x」表示這些變量之一;另一個翻譯單元中的名稱「x」表示另一個翻譯單位。因此,該計劃是不合格的。

+2

你如何得出結論,這兩個名字'x'不表示相同的變量? – ecatmur

+1

@ecatmur:有兩個變量,因爲有兩個定義:'int x;'定義一個具有靜態存儲持續時間的變量。有兩個這樣的定義,因此有兩個變量。如果程序按照Luc Danton的建議進行了修改,那麼只會有一個變量,因爲只有一個定義('extern int x;'不是'_的_definition_';它只是一個_declaration_)。 –

+0

如果不是'int x;'聲明的形式是'class y {};'或'namespace z {}'(兩個定義),那麼名稱'y'和'z'將分別表示相同的類型或名稱空間。變量'x'有什麼不同? – ecatmur

0

在編譯時沒有錯誤,錯誤在於它的鏈接。默認情況下,全局變量或函數都是公開的其他文件(有extern存儲),所以在連接時要鏈接的代碼到底看到兩個定義x,也不能選擇其中之一,所以如果你不使用在other.cpp和副詩句main.cppx使其靜態的(這意味着只包含它的文件可見)

// other.cpp 
static int x; 

// main.cpp 
static int x; 
1

如果標準不說有關未使用的變量的定義什麼,那麼你可以不意味着有可能是多個:

未定義的行爲也可能是預期的d當這個國際 標準忽略了任何明確的定義 行爲的描述。

所以它可以編譯和運行很好或錯誤信息轉換過程中可能會停止或發生故障運行時間等

編輯:見詹姆斯McNellis回答確實標準實際上有一個關於它的規則。

+0

該程序不會顯示未定義的行爲;它是不合格的。它違反了可診斷的語義規則。 –

+0

@詹姆斯是的,這是病態形成的,但我還是說認爲,如果標準忽略了描述的東西,然後它始終沒有定義發生了什麼,讀者可能不只是意味着隨意的事情。 –

5

你是正確的,該標準是在這方面的故障。我有一種感覺,這種情況下落入3.2p1之間的差距(以每翻譯單元最多一個定義,你的問題)和3.2p6(描述類,枚舉,內聯函數,以及各種模板,如何纔能有重複定義翻譯單位)。

爲了進行比較,在C,6.9p5要求(我的強調):

外部的定義是,也是功能 的定義(比內聯定義其他)或外部聲明目的。如果在表達式中使用由外部鏈接聲明的標識符(除了作爲操作數的一部分,而操作數的結果是一個整數常量),則在整個程序中的某處應該只有一個標識符的外部定義; 否則,不得有超過一個

相關問題