1.揭密extern "C"
extern "C"包含雙重含義,從字面上即可得到:首先,被它修飾的目標是 "extern”的;其次,被它修飾的目標是 "C”的。
首先來看一下 "extern”的含義:
a.在一個檔案內,如果外部變數不在檔案的開頭定義,其有效範圍只限定在定義到檔案的結束處。如果在定義前需要引用該變數,則要在引用之前用關鍵字 "extern” 對該變數做“外部變數聲明”,表示該變數是一個已經定義的外部變數。有個這個聲明,就可以從聲明處起合理地使用該變數了。"extern”起到了擴充範圍的作用。
//.c#include <stdio.h>void main(){ extern A;//用extern聲明外部變數;若變數為int類型,類型名可寫也可以省略。 printf("%d", A);}int A=100;
b.在多檔案的程式中,如果多個檔案都要使用同一個外部變數,不能在各個檔案中各定義一個外部變數,否則會出現“重複定義”的錯誤。正確的做法是:在任一個檔案中定義外部變數,其他檔案用 "extern”對變數做“外部變數聲明”。在編譯和串連時,系統會由此知道該變數是一個已經在別處定義的外部變數,並把另一檔案中外部變數的範圍擴充到本檔案,這樣在本檔案就可以合法地使用該外部變數了。
//file1.c#include <stdio.h>int A = 100;//定義外部變數void main(){ printf("%d",power());}//file2.cextern A;//聲明A為一個已定義的外部變數int power(){ return A*A;}
extern只用作聲明,而不用於定義。extern說明變數或者函數定義在其他的源檔案裡,而不用include標頭檔的方式來引用該函數,在連結時,連結器在各個模組中搜尋這個變數或者函數來進行最終連結。
c.外部函數
在定義函數時,如果在最左端加關鍵字extern,表示此函數是外部函數。C語言規定,如果在定義時省略extern,則隱含為外部函數。而內建函式必須前加static關鍵字;
在需要調用此函數的檔案中,用extern對函數作聲明,表示該函數是在其他檔案中定義的外部函數。
"C”的含義:(extern “C”)
C++通過函數參數的不同類型支援重載機制,編譯器根據參數為每個重載函數產生不同的內部標識符。例如編譯器為void Eat(Beef …);void Eat(Fish …);void Eat(Chicken …);三個Eat 函數產生象_eat_beef、_eat_fish、_eat_chicken 之類的內部標識符(不同的編譯器可能產生不同風格的內部標識符)。
如果 C++程式要調用已經被編譯後的C 函數,該怎麼辦?
假設某個 C 函數的聲明如下:
void foo(int x, int y);
該函數被C 編譯器編譯後在庫中的名字為_foo,而C++編譯器則會產生像_foo_int_int之類的名字用來支援函數重載和型別安全串連。由於編譯後的名字不同,C++程式不能直接調用C 函數。C++提供了一個C串連交換指定符號extern“C”來解決這個問題。
例如:
extern “C”{void foo(int x, int y);… // 其它函數}或者寫成extern “C”{#include “myheader.h”… // 其它C 標頭檔}
這就告訴C++編譯譯器,函數foo 是個C 串連,應該到庫中找名字_foo 而不是找_foo_int_int。C++編譯器開發商已經對C 標準庫的標頭檔作了extern“C”處理,所以我們可以用#include 直接引用這些標頭檔。
2.extern "C"程式執行個體
假設有C檔案:
//c.h#ifndef _C_H_#define _C_H_extern int add(int x, int y);#endif
//c.cint add(int x, int y){ return x+y;}
在C++下調用add()函數
//cplusplus.cpp#include <iostream>#include "c.h"using namespace std;void main(){ add(1, 0); system("Pause");}
產生錯誤:無法解析的外部符號 "int __cdecl add(int,int)" (?add@@YAHHH@Z),該符號在函數 _main 中被引用
為瞭解決這個問題,我們需要使用extern "C"。改寫C檔案
//c.h#ifndef _C_H_#define _C_H_#ifdef __cplusplusextern "C" {#endifextern int add(int x, int y);#ifdef __cplusplus}#endif#endif
檔案為*.c,__cplusplus沒有被定義,extern "C" {}這時沒有生效,對於C語言只是extern int add(int, int);而編譯c++源檔案,__cplusplus被定義,對於C++他看到的是extern "C" {extern int add(int, int);},編譯器就會知道add(1, 0)調用的是C串連。
最後:很多DLL的組建檔案(XXX.c)中常出現extern "C" ,windows採用C語言編譯建立dll,C程式可以正確調用DLL,而當使用者使用C++調用DLL時,extern "C" {}就起作用了。