當我嘗試在類的接口上方的頭文件中定義C函數時,我總是會收到構建錯誤。爲什麼我不能在頭文件中定義純C函數?
但是當我在執行文件中做同樣的事情並在頭文件中聲明時。事情解決。
我想知道,爲什麼這麼說因爲我已經在頭文件中定義了枚舉,結構,常量NSString,所以爲什麼不使用C函數呢?
當我嘗試在類的接口上方的頭文件中定義C函數時,我總是會收到構建錯誤。爲什麼我不能在頭文件中定義純C函數?
但是當我在執行文件中做同樣的事情並在頭文件中聲明時。事情解決。
我想知道,爲什麼這麼說因爲我已經在頭文件中定義了枚舉,結構,常量NSString,所以爲什麼不使用C函數呢?
這與C鏈接器(或鏈接編輯器)的工作方式有關。當C編譯器遇到函數定義時,它會準備實現該函數的彙編程序代碼,並用一個符號來標記它,它告訴鏈接程序「這是具有此名稱的函數開始的地方」。該符號通常以下劃線和函數名稱命名,例如, _printf
。
如果您在頭文件中定義函數,那麼導入該頭文件的每個.c
或.m
文件將編譯該函數,並且會導致編譯器發出相同的符號。鏈接器期望只找到每個符號的一個實例,所以這是一個錯誤。
這與#include
警衛的存在或使用#import
而不是#include
無關。 C編譯器適用於個別的翻譯單元 - 這意味着各個源文件。預處理器策略會阻止您將同一頭文件兩次包含到單個源文件中,但無法協調跨多個文件的活動。這意味着在不同的源文件中包含相同的頭文件是有效的:這也意味着當您編譯不同的文件時,他們可以(合法地)包含相同的符號。
鏈接編輯器的工作是將這些文件放在一起,解決對編譯時未知的符號的引用。如果嘗試將具有相同符號的對象(編譯和裝配的翻譯單元的名稱)鏈接到相同的存檔,共享庫或可執行文件中,則會看到您在此處看到的錯誤。
解決方案:
inline
定義標題中的函數。內聯函數只是被編譯器複製到它們被調用的函數中,所以鏈接器符號從不爲它們發射。這有你自己的權衡,你may wish to read more about。
shuldn't #import(而不是#include)只包含一個文件一次?並且..你也可以使用包括守衛(#ifndef MYFILE_H #define MYFILE_H ... #endif) – Francesco 2012-04-20 08:13:57
感謝@Francesco這個問題,我已經在上面加入了一個答案(簡短的版本是預處理器看守不會停止你得到鏈接錯誤)。 – 2012-04-20 08:36:34
但是..我們在談論C函數的定義或聲明嗎?因爲..我已經在.h文件中嘗試了一個函數定義,並且包含了該文件的兩倍。如果我使用#include,則會得到函數的「重新定義」。如果我使用#import或guard(在每個.h文件中),我不會收到任何錯誤...... – Francesco 2012-04-20 08:54:49