2011-09-28 110 views
5

許多C++項目(例如,許多Boost庫)「僅標題鏈接」。僅標題鏈接

這也可能在普通C?如何將源代碼放入標題中?有沒有關於它的網站?

+0

您的工作方式與C++中的完全相同。包含頭文件是C預處理器功能。 – avakar

+0

但是你擁有所有這些靜態函數和公共函數,我想這並不容易。 – Cartesius00

回答

11

執行摘要:您可以,但您不應該。

在編譯之前,C和C++代碼是預處理:所有頭以遞歸方式「粘貼」到包含它們的源文件中。如果在標題中定義了一個函數,並且它包含在兩個C文件中,那麼每個目標文件中將會有兩個副本(One Definition Rule違例)。

如果您的所有功能都標記爲static,即在翻譯單元外部不可見,則可以創建「僅標題」C庫。但這也意味着您將獲得包含頭文件的每個翻譯單元中的所有靜態函數的副本。在C++中有一點不同:內聯函數不是static,編譯器發出的符號仍然可以被鏈接器看到,但鏈接器可以丟棄重複內容,而不是放棄(「弱」符號)。

除非是基於宏(例如queue(3)),否則在頭文件中編寫C代碼並不是慣用的。在C++中,在頭文件中保留代碼的主要原因是模板,這可能會導致不同模板參數的代碼實例化,這不適用於C.

+0

+1:涵蓋了我想的所有基礎。 –

4

您不鏈接標題。

在C++中,編寫在頭文件中已經比在單獨編譯的模塊中更好的代碼稍微容易一些,因爲模板需要它。

但是,您也可以使用inline關鍵字作爲函數,它存在於C和C++中。

// Won't cause redefinition link errors, because of 6.7.4/5 
inline void foo(void) { 
    // ... 
} 

[c99: 6.7.4/5:]inline功能 符聲明的函數是一個內聯函數功能說明符可能會多次出現 ;行爲與僅出現一次的行爲相同。 使函數成爲內聯函數表明對函數 的調用盡可能快。這些建議的有效程度是由實施定義的。

不過,對於數據對象,你有點卡住了。


- 排序的。
- C99肯定。 C89/C90我必須檢查。

+0

您的意思是靜態關鍵字?因爲內聯只是編譯器的建議,可以完全忽略。 – Cartesius00

+0

@James:不,我的意思是「內聯」。儘管'inline'只是一個提示,編譯器不需要物理內聯函數,它對函數鏈接的影響很明確,並且必須由實現來觀察。否則,你怎麼知道你的'inline'函數有什麼聯繫? –

+0

哦,我明白了,C和C++不同,不是嗎? – Cartesius00

4

加速使大量使用模板和模板元編程,你不能效仿(所有易)在C.

但你當然可以通過其聲明和代碼在C頭文件,你#include但是這是欺騙不是一回事。我會說「當在羅馬......」和程序C根據C慣例與圖書館。

+0

我發現「在羅馬時......」是一個很好的答案。謝謝:) – Cartesius00

+0

很高興能有所幫助。隨意接受它,只要您在審查時仍將其視爲最佳答案即可。 –

3

是的,這是完全可能的。在頭文件中聲明所有函數,或者全部爲static,或者在項目中只使用一個編譯單元(即只有一個c文件)。作爲一個個人軼事,我知道很多物理學家堅持認爲這種技術是編程C的唯一真正方法。這是有益的,因爲它是窮人的版本-fwhole-program,即基於函數行爲可能。這很實用,因爲您不需要了解使用鏈接器標誌。這是一個糟糕的主意,因爲您的整個程序必須作爲一個整體進行編譯並重新編譯每一個小改動。

就我個人而言,我建議讓它成爲或者至少與static一起用於少數功能。

+0

答案並沒有用這種方法指出眩目的洞。 –

+0

@ TomalakGeret'kal:哪個明亮的洞? – thiton

+0

'static'給你每個TU的副本。真的,所有其他答案都提到了這些漏洞。 –