2012-04-20 23 views
8

當我嘗試在類的接口上方的頭文件中定義C函數時,我總是會收到構建錯誤。爲什麼我不能在頭文件中定義純C函數?

但是當我在執行文件中做同樣的事情並在頭文件中聲明時。事情解決。

我想知道,爲什麼這麼說因爲我已經在頭文件中定義了枚舉,結構,常量NSString,所以爲什麼不使用C函數呢?

回答

14

這與C鏈接器(或鏈接編輯器)的工作方式有關。當C編譯器遇到函數定義時,它會準備實現該函數的彙編程序代碼,並用一個符號來標記它,它告訴鏈接程序「這是具有此名稱的函數開始的地方」。該符號通常以下劃線和函數名稱命名,例如, _printf

如果您在頭文件中定義函數,那麼導入該頭文件的每個.c.m文件將編譯該函數,並且會導致編譯器發出相同的符號。鏈接器期望只找到每個符號的一個實例,所以這是一個錯誤。

這與#include警衛的存在或使用#import而不是#include無關。 C編譯器適用於個別的翻譯單元 - 這意味着各個源文件。預處理器策略會阻止您將同一頭文件兩次包含到單個源文件中,但無法協調跨多個文件的活動。這意味着在不同的源文件中包含相同的頭文件是有效的:這也意味着當您編譯不同的文件時,他們可以(合法地)包含相同的符號。

鏈接編輯器的工作是將這些文件放在一起,解決對編譯時未知的符號的引用。如果嘗試將具有相同符號的對象(編譯和裝配的翻譯單元的名稱)鏈接到相同的存檔,共享庫或可執行文件中,則會看到您在此處看到的錯誤。

解決方案:

  • 不要定義在頭的功能,只是聲明它那裏,在實現文件中定義它;因爲你已經發現這個作品。
  • 在頭文件中定義函數,但只在代碼的一個地方包含該頭文件。由於設計原因,這通常是不可接受的。
  • 使用修飾符inline定義標題中的函數。內聯函數只是被編譯器複製到它們被調用的函數中,所以鏈接器符號從不爲它們發射。這有你自己的權衡,你may wish to read more about
+0

shuldn​​'t #import(而不是#include)只包含一個文件一次?並且..你也可以使用包括守衛(#ifndef MYFILE_H #define MYFILE_H ... #endif) – Francesco 2012-04-20 08:13:57

+1

感謝@Francesco這個問題,我已經在上面加入了一個答案(簡短的版本是預處理器看守不會停止你得到鏈接錯誤)。 – 2012-04-20 08:36:34

+0

但是..我們在談論C函數的定義或聲明嗎?因爲..我已經在.h文件中嘗試了一個函數定義,並且包含了該文件的兩倍。如果我使用#include,則會得到函數的「重新定義」。如果我使用#import或guard(在每個.h文件中),我不會收到任何錯誤...... – Francesco 2012-04-20 08:54:49

相關問題