【轉載】extern "C"

extern "C"包含雙重含義,其一:被它修飾的目標是“extern”的;其二:被它修飾的目標是“C”的。
1)被extern “C”限定的函數或變量是extern類型的;
    extern是C/C++語言中表明函數和全局變量作用範圍(可見性)的關鍵字,該關鍵字告訴編譯器,其聲明的函數和變量可以在本模塊或其他模塊中使用。
    注意:extern int a;
    僅僅是在聲明一個變量,並不是定義變量a,並未爲a分配內存空間。變量a在所有模塊中作爲一種全局變量只能被定義一次,否則會出現連接錯誤。
    通常,在模塊的頭文件中對模塊提供給其他模塊引用的函數和全局變量以關鍵字extern聲明。例如,如果模塊B欲引用該模塊A中定義的全局變量和函數時只 需包含模塊A的頭文件即可。這樣,模塊B中調用模塊A中的函數時,在編譯階段,模塊B雖然找不到該函數,但是並不會報錯,它會在連接階段中從模塊A編譯生 成的目標代碼中找到此函數。
    與extern對應的關鍵字是static,被它修飾的全局變量和函數只能在本模塊中使用。因此,一個函數或變量只可能被本模塊使用時,其不可能被extern "C"修飾。
2)被extern "C"修飾的變量和函數是按照C語言方式編譯和連接的
    作爲一種面向對象的語言,C++支持函數重載,而過程式語言C則不支持。函數被C++編譯後在符號庫中的名字與C語言的不同。例如,假設某個函數的原型爲:void foo(int x, int y);
該函數被C編譯器編譯後在符號庫中的名字爲_foo,而C++編譯器則會產生像_foo_int_int之類的 名字(不同的編譯器可能產生的名字不同,但是都採用了相同的機制)。_foo_int_int這樣的名字包含了函數名、函數參數數量及類型信息,C++就 是靠這種機制來實現函數重載的。例如,在C++中,函數void foo(int x, int y)與void foo(int x, float y)編譯產生的符號是不相同的,後者爲_foo_int_float。
    extern "C"作用:實現C++與C及其它語言的混合編程。
3)extern "C"的慣用法
A)在C++中引用C語言中的函數和變量,在包含C語言頭文件(假設爲cExample.h)時,需進行下列處理:
extern "C"
{
#include "cExample.h"
}
    而在C語言的頭文件中,對其外部函數只能指定爲extern類型,C語言中不支持extern "C"聲明,在.c文件中包含了extern "C"時會出現編譯語法錯誤。
    例如:
/*c語言頭文件:cExample.h*/
#ifndef C_EXAMPLE_H
#define C_EXAMPLE_H
extern int add(int x, int y);
#endif
/*c語言實現文件:cExample.c*/
#include "cExample.h"
int add(int x, int y)
{
    return x+y;
}
//c++實現文件,調用add:cppFile.cpp
extern "C"
{
#include "cExample.h"
}
int main(int argc, char *argv[])
{
    add(2,3);
    return 0;
}
B)在C中引用C++語言中的函數和變量時,C++的頭文件需添加extern "C",但是在C語言中不能直接引用聲明瞭extern "C"的頭文件,應該僅將C文件中將C++中定義的extern "C"函數聲明爲extern類型。
例如:
//C++頭文件 cppExample.h
#ifndef CPP_EXAMPLE_H
#define CPP_EXAMPLE_H
extern "C" int add(int x, int y);
#endif
//C++實現文件 cppExample.cpp
#include "cppExample.h"
int add(int x, int y)
{
    return x+y;
}
/*C實現文件cFile.c
/*這樣會編譯出錯:#include "cExample.h"*/
extern int add(int x, int y);
int main(int argc, char *argv[])
{
    add(2,3);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章