C/C++採用的是分別編譯模型, 源代碼只要聲明函數, 就可調用。函數
編譯時,在函數調用處生成一個符號引用。spa
連接時,將函數調用處的符號引用,替換成地址(甚至仍有可能繼續保留符號, 載入時再計算地址)。翻譯
因此, 如下二者必須徹底比配, 不然連接時會出錯。
code
1. 函數調用處引用的符號名編譯器
2. 函數定義處公開的符號名編譯
如何使得二者匹配?
class
不管是在調用處仍是在定義處, 不管是C仍是C++(注1), 編譯器都會對函數名進行mangling, 產生一個符號名。引用
而 extern "C" 就是通知C++編譯器(注2), 將某函數按照C的規則進行mangling, 產生符號名。di
若是是在聲明處使用 extern "C", 函數調用處引用的符號名將按C的mangling規則產生。co
若是是在定義處使用 extern "C", 翻譯單元裏公開的符號名將按C的mangling規則產生。
同時, C編譯器將 extern "C" 視爲錯誤—— 因此須要相似的代碼:
#ifdef __cplusplus extern "C" { #endif /*...*/ #ifdef __cplusplus } #endif
extern "C" 一般使用的地方。
1. 當一個函數已經由C編譯器實現
在一個C++翻譯單元中, 必須使用 extern "C" 聲明改函數。
這樣, 該函數調用產生的符號名引用和已經由C編譯器實現的函數的符號名才能匹配。
2. 用C++編譯器實現C和C++均可調用的函數。
本身聲明extern 「C」。 在C++翻譯單元中, 該函數名按C規則修飾以後, 獲得符號名, 並公開。
C++的調用者依然須要使用 extern "C" 來聲明。
C的調用者直接聲明。
目的也是爲了使得引用與實現的符號名匹配。