2011-08-14 23 views
1

(我正在談論C,但它也適用於C++中的類模板)爲什麼結構定義有內部聯繫?

在頭文件中,放置所有聲明,而不是定義是自定義的。但是,我們通常會將結構定義或類模板放在頭文件中,而實際上並不知道爲什麼可以。這並沒有什麼意義,因爲它們也是定義 - 一個定義規則。 (是的,結構定義和類模板不會導致任何存儲設置,但您仍然會得到「重定義」錯誤,低於此錯誤意味着它們是定義)。在相同的文件中定義多個具有相同標記的結構給你一個重定義錯誤,但是在多個源文件中定義具有相同標記的多個結構不會導致任何錯誤(同樣的事情發生在類中)。

唯一有意義的是結構定義和類模板具有內部鏈接(與默認的外部鏈接相對),但是我無法在K & R或參考手冊中找到任何關於它的參考。事實上,連結中甚至沒有提到結構。

我想知道ANSI標準指出這個現象的確切參考。 (國際海事組織,這是一個非常模糊的東西,有必要在ANSI標準中提到)。


編輯 我不問爲什麼結構定義可以被放入頭文件。

我問爲什麼把結構定義在頭文件中,當我們把在頭文件變量定義(並將其包含在多個源文件)

EX) test1.c像它不會導致重新定義錯誤:int a = 3; test2.c:int a = 4; 由於重新定義而導致編譯錯誤。但是,

test1.c:struct test {int a}; test2.c:struct test {int b}; 不會導致編譯錯誤,我能想出的唯一原因是 結構定義或者有內部鏈接,或者根本沒有鏈接。

+0

什麼是 「內部」 鏈接 - 你的意思是 「靜態」? –

+0

內部鏈接定義在http://publications.gbdirect.co.uk/c_book/chapter8/declarations_and_definitions.html – SHH

+0

標準C具有「暫定義」的概念。嘗試在K&R或參考手冊中查找。 – pmg

回答

4

在C中只有對象和函數有聯繫。由於C中的struct可能不包含函數或C++中的「static」成員對象,因此您的問題在這裏沒有多大意義。

C++中的成員函數只要它們沒有被定義,但只在struct內聲明沒有問題。如果他們也被定義,他們是inlineinline的概念剛剛發明了C++來捕獲這種情況:函數定義可以通過多個編譯單元中的頭文件共享。 C99採用了這個概念(略微修改)。

static成員對象的確造成了更多的問題。關於如何實例化這些傢伙的語法很不明確,特別是對於templateclass es或struct s。如果你想知道那個,你必須要求這個,用C++專門標記。

+0

結構標識符沒有鏈接。這是答案。非常感謝你!我從ANSI標準規範中驗證了這一事實:「以下標識符沒有鏈接:標識符被聲明爲除對象或函數以外的任何東西;」 http://flash-gordon.me.uk/ansi.c.txt – SHH

0

結構在頭文件中定義,因爲頭文件提供了模塊的接口。當結構的接口定義,有可能接口的用戶:

  • 指的是結構的成員
  • 知道結構有多大 - 否則他們無法分配內存結構

鏈接與它無關 - 只有鏈接的功能,而不是數據結構。

請注意,您仍然可以在頭文件中聲明結構,如果要隱藏結構的內部結構(不透明數據結構),這非常有用。接口的用戶可以擁有指向結構的指針,並將它們用作cookie的一種,但是它們不能自己分配這樣的結構,或者不能在其中「查看」。

至於沒有得到在頭文件中定義的結構時,重新定義錯誤,那是因爲頭警衛簡單地 - 頭通常是這樣的:

#ifdef MYHEADER_H 
#define MYHEADER_H 

struct a { int x; } 
void f(void); 
/* and so on */ 

#endif 

所以包含一個頭文件時,它是通常只包含一次,因此每個翻譯文件只定義一次結構。鏈接器與結構定義無關,因爲它們沒有鏈接。

+0

我想你也錯過了我的觀點:/參考編輯。 – SHH

+0

我希望現在更清楚。 – Antti

+0

'#ifdef'應該是'#ifndef' – Dave

0

我認爲你在這裏混淆了一下,你可以把你喜歡的任何東西放在頭文件中。

通常的東西放在他們是枚舉,類型定義,結構和函數原型的聲明,因此各種C文件可以編譯而無需知道實際功能或實際內存(一個結構基本上是定義內存被佈置)

+0

我想你錯過了我的觀點。是的,我們可以在頭文件中放入任何東西,但我們通常只是爲了避免重定義錯誤而放置聲明。但是,我只是想知道爲什麼頭文件中的結構定義不會在多個源文件中導致重定義錯誤。 – SHH

0

我沒有最終版本的拷貝,但是從n843 draft of the specification我看到:

6.7.2.3標籤

:「4點兩個聲明結構,聯合或枚舉類型的這是在不同的範圍或使用不同的標籤聲明不同的類型。不包含標籤的結構,聯合或枚舉類型的每個聲明都會聲明不同的類型。「

6.2.1作用域標識符:「4.每隔identi音響ER已範圍通過其聲明的位置決定的(在一個聲明符或鍵入SPECI音響ER)如果聲明瞭identi音響ER的說明符或鍵入SPECI音響ER出現的外任何塊或參數列表,標識符有文件範圍,它終止於翻譯單元的末尾。[...] [[原文爲重點])(我在本節提到的唯一標識符類型這個聲明是標籤,它具有函數範圍。)

我不是C或標準的專家,但它在我看來像這樣解釋了你所看到的行爲。因此,如果文件範圍相同且結構具有重複標記,那麼結構應該有衝突,因爲需要使用不同的標記來使它們具有不同的類型。但是,如果它們位於不同的文件範圍中,則不存在任何問題,因爲只要它們處於不同的範圍內,就可以滿足作爲不同類型的要求。

+0

至於C++中的模板,我不確定它是否是相同的原因;如果這不能回答你的問題,我可以嘗試追蹤C++規範。 – shelleybutterfly

+0

謝謝你的回答。正確的答案是結構沒有聯繫。你的回答讓我深入瞭解ANSI標準規範,並找到了答案。 「以下標識符沒有鏈接:一個標識符被聲明爲對象或函數以外的任何東西;」 flash-gordon.me.uk/ansi.c.txt – SHH

+0

和我很確定同樣的事情適用於類模板以及:) – SHH

1

結構行只是一個定義。該定義在源文件之外不可見。
供參考:兩個源文件都不導出任何內容。

爲了測試這個:

$ cat test1.c 
struct test { char a; }; 
$ gcc -o test1.o -c test1.c 
$ nm 
$ echo "struct test foo; " >> test1.c 
$ gcc -o test1.o -c test1.c 
$ nm 
0000000000000001 C _foo 
相關問題