extern C的作用詳解

2021-07-05 05:41:35 字數 3674 閱讀 6692

extern "c"的主要作用就是為了能夠正確實現c++**呼叫其他c語言**。加上extern "c"後,會指示編譯器這部分**按c語言的進行編譯,而不是c++的。由於c++支援函式過載,因此編譯器編譯函式的過程中會將函式的引數型別也加到編譯後的**中,而不僅僅是函式名;而c語言並不支援函式過載,因此編譯c語言**的函式時不會帶上函式的引數型別,一般之包括函式名。

這個功能十分有用處,因為在c++出現以前,很多**都是c語言寫的,而且很底層的庫也是c語言寫的,為了更好的支援原來的c**和已經寫好的c語言庫,需要在c++中盡可能的支援c,而extern "c"就是其中的乙個策略。

這個功能主要用在下面的情況:

1、c++**呼叫c語言**

2、在c++的標頭檔案中使用

3、在多個人協同開發時,可能有的人比較擅長c語言,而有的人擅長c++,這樣的情況下也會有用到

給出乙個我設計的例子:

modulea、moduleb兩個模組,b呼叫a中的**,其中a是用c語言實現的,而b是利用c++實現的,下面給出一種實現方法:

//modulea標頭檔案

#ifndef __module_a_h //對於模組a來說,這個巨集是為了防止標頭檔案的重複引用

#define __module_a_h

int fun(int, int);

#endif

//modulea實現檔案modulea.c //模組a的實現部分並沒有改變

#include"modulea"

int fun(int a, int b)

//moduleb標頭檔案

#idndef __module_b_h //很明顯這一部分也是為了防止重複引用

#define __module_b_h

#ifdef __cplusplus //而這一部分就是告訴編譯器,如果定義了__cplusplus(即如果是cpp檔案, extern "c"

#endif

#endif

//moduleb實現檔案 moduleb.cpp //b模組的實現也沒有改變,只是標頭檔案的設計變化了

#include"moduleb.h"

int main()

下面是詳細的介紹:

由於c、c++編譯器對函式的編譯處理是不完全相同的,尤其對於c++來說,支援函式的過載,編譯後的函式一般是以函式名和形參型別來命名的。

例如函式void fun(int, int),編譯後的可能是(不同編譯器結果不同)_fun_int_int(不同編譯器可能不同,但都採用了類似的機制,用函式名和引數型別來命名編譯後的函式名);而c語言沒有類似的過載機制,一般是利用函式名來指明編譯後的函式名的,對應上面的函式可能會是_fun這樣的名字。

看下面的乙個面試題:為什麼標準標頭檔案都有類似的結構?

#ifndef __incvxworksh /*防止該標頭檔案被重複引用*/

#define __incvxworksh

#ifdef __cplusplus             //告訴編譯器,這部分**按c語言的格式進行編譯,而不是c++的

extern "c"

#endif

#endif /*end of __incvxworksh*/

分析:

#ifdef __cplusplus (其中__cplusplus是cpp中自定義的乙個巨集!!!)

extern "c"

#endif

的作用是什麼呢?

extern "c"包含雙重含義,從字面上可以知道,首先,被它修飾的目標是"extern"的;其次,被它修飾的目標**是"c"的。

extern是c/c++語言中表明函式和全域性變數的作用範圍的關鍵字,該關鍵字告訴編譯器,其申明的函式和變數可以在本模組或其他模組中使用。

記住,下面的語句:

extern int a; 僅僅是乙個變數的宣告,其並不是在定義變數a,並未為a分配空間。變數a在所有模組中作為一種全域性變數只能被定義一次,否則會出錯。

通常來說,在模組的標頭檔案中對本模組提供給其他模組引用的函式和全域性變數以關鍵字extern生命。例如,如果模組b要引用模組a中定義的全域性變數和函式時只需包含模組a的標頭檔案即可。這樣模組b中呼叫模組a中的函式時,在編譯階段,模組b雖然找不到該函式,但並不會報錯;它會在鏈結階段從模組a編譯生成的目標**中找到該函式。

extern對應的關鍵字是static,static表明變數或者函式只能在本模組中使用,因此,被static修飾的變數或者函式不可能被extern c修飾。

上面也提到過,由於c++支援函式過載,而c語言不支援,因此函式被c++編譯後在符號庫中的名字是與c語言不同的;c++編譯後的函式需要加上引數的型別才能唯一標定過載後的函式,而加上extern "c"後,是為了向編譯器指明這段**按照c語言的方式進行編譯

未加extern "c"宣告時的鏈結方式:

//模組a標頭檔案 modulea.h

#idndef _module_a_h

#define _module_a_h

int foo(int x, int y);

#endif

在模組b中呼叫該函式:

//模組b實現檔案 moduleb.cpp

#include"modulea.h"

foo(2,3);

實際上,在鏈結階段,聯結器會從模組a生成的目標檔案modulea.obj中找_foo_int_int這樣的符號!!!,顯然這是不可能找到的,因為foo()函式被編譯成了_foo的符號,因此會出現鏈結錯誤。

常見的做法可以參考下面的乙個實現:

modulea、moduleb兩個模組,b呼叫a中的**,其中a是用c語言實現的,而b是利用c++實現的,下面給出一種實現方法:

//modulea標頭檔案

#ifndef __module_a_h //對於模組a來說,這個巨集是為了防止標頭檔案的重複引用

#define __module_a_h

int fun(int, int);

#endif

//modulea實現檔案modulea.c //模組a的實現部分並沒有改變

#include"modulea"

int fun(int a, int b)

//moduleb標頭檔案

#idndef __module_b_h //很明顯這一部分也是為了防止重複引用

#define __module_b_h

#ifdef __cplusplus //而這一部分就是告訴編譯器,如果定義了__cplusplus(即如果是cpp檔案, extern "c"

#endif

#endif

//moduleb實現檔案 moduleb.cpp //b模組的實現也沒有改變,只是標頭檔案的設計變化了

#include"moduleb.h"

int main()

extern "c"的使用要點

1. 可以是單一語句

extern "c" double sqrt(double);

2. 可以是復合語句, 相當於復合語句中的宣告都加了extern "c"

extern "c"

3.可以包含標頭檔案,相當於標頭檔案中的宣告都加了extern "c"

extern "c"

4. 不可以將extern "c" 新增在函式內部

5. 如果函式有多個宣告,可以都加extern "c", 也可以只出現在第一次宣告中,後面的宣告會接受第乙個鏈結指示符的規則。

6. 除extern "c", 還有extern "fortran" 等。

extern C的作用詳解

extern c 的主要作用就是為了能夠正確實現c 呼叫其他c語言 加上extern c 後,會指示編譯器這部分 按c語言的進行編譯,而不是c 的。由於c 支援函式過載,因此編譯器編譯函式的過程中會將函式的引數型別也加到編譯後的 中,而不僅僅是函式名 而c語言並不支援函式過載,因此編譯c語言 的函式...

extern C的作用詳解

1.引言 c 語言的建立初衷是 a better c 但是這並不意味著c 中類似c語言的全域性變數和函式所採用的編譯和連線方式與c語言完全相同。作為一種欲與c相容的語言,c 保留了一部分過程式語言的特點 被世人稱為 不徹底地物件導向 因而它可以定義不屬於任何類的全域性變數和函式。但是,c 畢竟是一種...

extern C的作用詳解

extern c 的主要作用就是為了能夠正確實現c 呼叫其他c語言 加上extern c 後,會指示編譯器這部分 按c語言的進行編譯,而不是c 的。由於c 支援函式過載,因此編譯器編譯函式的過程中會將函式的引數型別也加到編譯後的 中,而不僅僅是函式名 而c語言並不支援函式過載,因此編譯c語言 的函式...