2014-01-27 60 views
8

比方說,我有三個文件:爲什麼我不能在C中得到'多重定義'的枚舉?

//m.h 
const int RED = 1; 
//m.h ends here 

//f1.c 
#include "m.h" 
//f1.c ends here 


//f2.c 
#include "m.h" 
int main() {return 0;} 
//f2.c ends here 

編譯每一個單獨的工作,但gcc -Wall f1.o f2.o -o prog會產生: multiple definition of 'RED'

現在如果我更換常量:

//m.h 
enum {RED=1} colors; 
//m.h ends here 

我將能夠編譯prog並使用RED作爲常量,並且不會得到任何multiple definition錯誤。

爲什麼enum的行爲與在不同文件中具有相同名稱的全局變量或結構時可見的行爲不同?

+0

究竟是什麼命令行給你的錯誤? (你應該在'.h'文件中'en''定義'f1.c'和'f2.c'包含'#include';對象定義應該在'.c'文件中。) –

+0

這就是我的意思,但忘了補充。我將編輯該問題。 – Paz

+0

您的命令'gcc -Wall f1.o f2.o -o prog'使用現有的* .o'文件,您必須使用早期的'gcc -c ...'命令生成該文件。如果您要更改源文件,很可能您的'.o'文件與您的'.c'文件不符。如果您編譯並鏈接到單個命令中,您是否可以重現該問題? 'gcc -Wall f1.c f2.c -o prog' –

回答

3

枚舉不會在內存中創建值,這意味着鏈接時沒有地址添加到符號表中。

const變量將在編譯對象中有一個地址,並帶有一個符號名稱。當您嘗試將兩個目標文件鏈接在一起時,它們都具有相同的符號名稱「RED」,指向不同的地址,這是導致衝突的原因。

+1

我喜歡你清楚的解釋。謝謝! – Paz

4

枚舉常量不是對象,它們在可執行文件中只有一個值但沒有分配。因此,在第二個示例中,RED只是每個文件中值的定義。另一方面,color不是你所想的。這是一個名爲color的對象的「暫定義」。如果你不使用它,它不會被分配,並且一切似乎都很好。但它似乎是如此。

在第一個示例中,您在每個文件中都有一個const限定對象名爲RED。由於它被初始化,所以這是一個定義,並且在每個.o文件中都會生成符號。因此,鏈接器的投訴。

+0

因此它似乎(至少在一個「淺」的意義上)枚舉比常量更接近宏定義。那是對的嗎? – Paz

+1

我不會稱它們爲宏定義。但是這些值是編譯時常量。 –

+0

enum常量*是*常量,但是在C標準的行話中,const限定的對象不是「常量」。 'enum'常量有一個類型(令人驚訝的是'int')。宏是完全不同的。它們是文本替換,*可能會發生擴展爲文字,但也可能擴展爲完全不同的東西(變量,函數調用或什麼也不是)。 –

相關問題