extern C 與函式過載

2022-07-03 15:12:15 字數 3949 閱讀 7957

如果向要在乙個檔案中使用另乙個檔案中的變數,不能在標頭檔案中定義全域性變數,因為被多個檔案包含後會導致編譯出錯,並且靜態的static變數,只能在本檔案內使用,這時候就可以使用extern關鍵字。

首先還是先看一下 extern 關鍵字的作用:extern關鍵字可以置於變數或函式前,以標示變數或函式的定義在別的檔案中,提示編譯器遇到此變數或函式時在其他模組中尋找其定義。

通常情況下,比如我們在標頭檔案  "b.h"  中宣告了乙個函式,然後在 "b.cpp" 中實現了該函式,當在 "main.cpp" 中呼叫 "b.h" 中宣告的函式時,只需要在 ""main.cpp" 中 #include "b.h" 就可以了。例子如下:

1

2#ifndef _b_

3#define _b_

45 #include6

using

namespace

std;78

void

test();910

#endif

//_b_

1 #include "

b.h"

2void

test()

3

1 #include2 #include"

b.h"34

using

namespace

std;56

intmain()

7

除了通過 #include "b.h" 這樣的方式能呼叫到 "b.h" 中的函式外,還有下面這種方式也能呼叫到"b.h" 的函式。

1 #include2

//#include"b.h"

//在這裡,不注釋掉也是可以得,但是在對於 變數 來說時就必須注釋掉了34

using

namespace

std;56

extern

void test(); //

告訴編譯器test()函式宣告在其他檔案中78

intmain()

9

上面是對於函式而言,那麼要是在 "b.h" 中定義了乙個全域性變數 int x,(記住是全域性變數哦!)現在我們想在 "main.cpp" 中訪問變數 x, 那該怎麼辦呢? 會不會 #include "b.h" 後就可以直接訪問了呢?我們先試一下:

1

2#ifndef _b_

3#define _b_

45 #include6

using

namespace

std;78

int x = 10;9

10void

test();

1112

#endif

//_b_

1

2 #include "

b.h"34

intmain()

5

我們在 "main.cpp" 中輸出變數 x, 在vs2017中會報錯。  (上乙個增量鏈結沒有生成它;正在執行完全鏈結,error lnk2005: "int x" (?x@@3ha) 已經在 b.obj 中定義)

通過 #include "b.h" 這種方式就想訪問到變數 x 太天真了,是訪問不到的,因為 "b.h" 的全域性變數 x 的訪問作用域是檔案作用域,它只能在 "b.h" 這個檔案中進訪問,記住是只能在 "b.h" 中進行訪問,在 "b.cpp"中通過 #include "b.h" 你也是不能訪問的。 那麼現在我們有沒有其他方式能在 "main.cpp" 中訪問到變數 x 呢?當然有,通過 "extern" 關鍵字能達到目的。用法如下:

1

2//#include "b.h"

//一定要注釋掉

3 #include 4

using

namespace

std;

5extern

intx;67

intmain()

8

說明:如果在乙個檔案中使用extren引入外部變數,在這個檔案中修改這個變數,就等於修改了該外部變數。

說了那麼多廢話,終於把 extern 關鍵字說清楚了。接下來這個才是extern "c" 。

要說清楚 extern "c" 是怎麼一回事,還得先說說c++函式過載的那些事。c++有函式過載,而c語言是沒有函式過載的。函式過載是指兩個或多個函式之間函式名相同,引數列表不同,引數列表不同可以是引數的個數不同,或者是引數的個數相同但引數型別不同,需要注意的是如果函式名相同,引數列表完全相同但返回值型別不同是不能構成函式過載的。c++有函式過載是因為當生成obj中間檔案/目標檔案的時候,c++編譯器把原函式名與引數資訊結合,產生了乙個獨特的內部名字,比如有兩個函式 void foo(int x) 和 void foo(void) ,最終產生的內部名字就是 _foo_int 和 _foo_void (實際產生的內部名字的命名規則應該不是這樣的,這裡我們並不關心它的命名規則是怎樣的,只需要體會這個意思就可以了),通過這樣編譯器就能區分 void foo(int x) 和 void foo(void)這兩個函式了。但是在c語言裡面,並不會產生這樣的內部名字,如果c語言裡面有兩個函式 void foo(int x) 和void foo(void),那麼當生成obj中間檔案/目標檔案的時候,產生的名字就是 _foo 和 _foo 這樣兩個名字相同,c編譯器就不能將兩個函式區分開了,所以c語言裡面也就沒了函式過載。

正是由於c++編譯器 和 c編譯器對函式名處理方式的不同,當我們的 c++ 程式呼叫 c 程式或者 c 程式呼叫 c++程式時就會存在問題。 有了問題那當然就得解決,於是就有了 extern "c" 的出現。

所以說到底 extern "c" 的作用是用來解決名字匹配問題,實現 c 與 c++ 的混合程式設計。擺這麼一句話在這裡顯得很蒼白無力,還是舉例說明一下。

c++中函式過載,編譯器的命名規則是

1

int fun(int a, intb)2

5char fun(char a, charb)6

910void

main()

11

上述c++的兩個過載函式被編譯器命名為下:

在不同的平台的編譯器中,命名規則不一定相同,其中的ddd和hhh代表返回值、第乙個引數型別、第二個引數型別

如果再加乙個引數

1

int fun(int a, int b, charc)2

命名會變為

可以得出,c++編譯器的函式命名規則

而在c語言中,編譯器將函式命名為

所以不論多少個函式,編譯器都會命名為一樣的函式,即使你的引數不一樣,編譯器也無法調動這個函式,所以就會報錯

在c++中加extern 「c」 

1

extern"c

"int fun(int a, intb)2

5extern"c

"char fun(char a, charb)6

910void

main()

11

上述c++程式中,加乙個extern "c"沒問題,加兩個就會報錯了,加了extern "c"就等於用c語言的方式編譯,函式的命名規則會變成c語言的,然而c語言不允許函式的過載。

在c++程式中呼叫被c編譯器編譯後的函式,加extern「c「宣告,為了預防函式的過載出現。

為什麼返回值不能確定函式過載,如果有以下程式

1

int fun(int a, intb)2

5char fun(int a, intb)6

如果按照c++編譯器的命名,這兩個函式的命名也是不同的,為什麼不能過載呢?

這時候並不是不行,而是呼叫乙個函式,可以呼叫乙個,也可以呼叫另乙個,然後編譯器並不知道要調到哪個,出現了二義性,而不同的函式引數,在編譯時就決定了呼叫哪個,編譯器也不知道要將返回值給哪個型別,所以僅靠返回值是不能用來過載函式的。

[參考:

extern C 與函式過載機制

先來看一下下面這道題 在c 程式中被c編譯器編譯後的函式,為什麼要加extern c 我們來寫乙個簡單的程式測試一下。先寫乙個c 程式,簡單的求兩個數的和。includeusing namespace std extern int add int int int main 1 test.obj er...

命名空間 預設引數 函式過載 extern C

2.預設引數 3.函式過載 4.extern c c 中的類和庫中有大量的關鍵字,那麼我們定義變數的時候就很容易與這些系統關鍵字發生衝突,使用命名空間的目的就是為了避免與關鍵字發生衝突 舉個簡單的例子,有人來學校找乙個叫張三的人,廣播出去後有非常多叫張三,這樣就導致了混淆,不知道你要找誰。但是你如果...

符號修飾與函式簽名 extern 「C」

程式設計師的自我修養 3.5.3以及3.5.4小節。符號修飾的由來 20世紀70年代以前,編譯器編譯 時產生的目標檔案中,符號名與相應的變數和函式的名字是一樣的,隨著程式語言的發展,例如c語言,如果乙個c語言程式要使用這些庫的話,其自身就不能使用這些庫中已經宣告了的函式和變數的名字作為符號名,否則將...