extern C的作用詳解,extern詳解

來源:互聯網
上載者:User

extern C的作用詳解,extern詳解

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)

{

return a+b;

}

//moduleB標頭檔

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

#define __MODULE_B_H

#ifdef __cplusplus //而這一部分就是告訴編譯器,如果定義了__cplusplus(即如果是cpp檔案, extern "C"{ //因為cpp檔案預設定義了該宏),則採用C語言方式進行編譯

#include"moduleA.h"

#endif

… //其他代碼

#ifdef __cplusplus

}

#endif

#endif

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

#include"moduleB.h"

int main()

{

cout<<fun(2,3)<<endl;

}

下面是詳細的介紹:

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

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

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

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

#define __INCvxWorksh

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

extern "C"{

#endif

/*…*/

#ifdef __cplusplus

}

#endif

#endif /*end of __INCvxWorksh*/

分析:

  • 顯然,標頭檔中編譯宏"#ifndef __INCvxWorksh 、#define __INCvxWorksh、#endif"(即上面代碼中的藍色部分)的作用是為了防止該標頭檔被重複引用
  • 那麼

#ifdef __cplusplus (其中__cplusplus是cpp中自訂的一個宏!!!)

extern "C"{

#endif

#ifdef __cplusplus

}

#endif

的作用是什麼呢?

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

  • 被extern "C"限定的函數或變數是extern類型的

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

記住,下面的語句:

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

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

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

  • 被extern "C"修飾的變數和函數是按照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)

{

return a+b;

}

//moduleB標頭檔

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

#define __MODULE_B_H

#ifdef __cplusplus //而這一部分就是告訴編譯器,如果定義了__cplusplus(即如果是cpp檔案, extern "C"{ //因為cpp檔案預設定義了該宏),則採用C語言方式進行編譯

#include"moduleA.h"

#endif

… //其他代碼

#ifdef __cplusplus

}

#endif

#endif

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

#include"moduleB.h"

int main()

{

cout<<fun(2,3)<<endl;

}

extern "C"的使用要點

1. 可以是單一語句

    extern "C" double sqrt(double);

2. 可以是複合陳述式, 相當於複合陳述式中的聲明都加了extern "C"

    extern "C"

   {

      double sqrt(double);

      int min(int, int);

  }

3.可以包含標頭檔,相當於標頭檔中的聲明都加了extern "C"

   extern "C"

  {

    #i nclude <cmath>

  }

4. 不可以將extern "C" 添加在函數內部

5. 如果函數有多個聲明,可以都加extern "C", 也可以只出現在第一次聲明中,後面的聲明會接受第一個連結指示符的規則。

6. 除extern "C", 還有extern "FORTRAN" 等。

參考文章:

extern C使用

extern c的作用【轉】_看雪..

extern C使用要點

http://blog.chinaunix.net/u/29619/showart_230148.html

http://blog.csdn.net/weiqubo/archive/2009/10/16/4681813.aspx

http://hi.baidu.com/sundl2268/blog/item/4969453d2258bae53c6d970a.html

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.