extern及extern “C”用法

來源:互聯網
上載者:User

標籤:ar   使用   strong   sp   檔案   on   問題   代碼   amp   

1 基本解釋extern可以置於變數或者函數前,以標示變數或者函數的定義在別的檔案中,提示編譯器遇到此變數和函數時在其他模組中尋找其定義。

  另外,extern也可用來進行連結指定。

  2 問題:extern 變數在一個源檔案裡定義了一個數組:char a[6];在另外一個檔案裡用下列語句進行了聲明:extern char *a;請問,這樣可以嗎?

  答案與分析:1)、不可以,程式運行時會告訴你非法訪問。原因在於,指向類型T的指標並不等價於類型T的數組。extern char *a聲明的是一個指標變數而不是字元數組,因此與實際的定義不同,從而造成運行時非法訪問。應該將聲明改為extern char a[ ].

  2)、例子分析如下,如果a[] = "abcd",則外部變數a=0x61626364 (abcd的ASCII碼值),*a顯然沒有意義

  顯然a指向的空間(0x61626364)沒有意義,易出現非法記憶體訪問。

  3)、這提示我們,在使用extern時候要嚴格對應聲明時的格式,在實際編程中,這樣的錯誤屢見不鮮。

  4)、extern用在變數聲明中常常有這樣一個作用,你在*.c檔案中聲明了一個全域的變數,這個全域的變數如果要被引用,就放在*.h中並用extern來聲明。

  3 問題:extern 函數1

  常常見extern放在函數的前面成為函式宣告的一部分,那麼,C語言的關鍵字extern在函數的聲明中起什麼作用?

  答案與分析:

  如果函數的聲明中帶有關鍵字extern,僅僅是暗示這個函數可能在別的源檔案裡定義,沒有其它作用。即下述兩個函式宣告沒有明顯的區別:

  extern int f(); 和int f();當然,這樣的用處還是有的,就是在程式中取代include “*.h”來聲明函數,在一些複雜的項目中,我比較習慣在所有的函式宣告前添加extern修飾。

  4 問題:extern 函數2

  當函數提供方單方面修改函數原型時,如果使用方不知情繼續沿用原來的extern申明,這樣編譯時間編譯器不會報錯。但是在運行過程中,因為少了或者多了輸入參數,往往會照成系統錯誤,這種情況應該如何解決?

  答案與分析:

  目前業界針對這種情況的處理沒有一個很完美的方案,通常的做法是提供方在自己的xxx_pub.h中提供對外部介面的聲明,然後調用方include該標頭檔,從而省去extern這一步。以避免這種錯誤。

  寶劍有雙鋒,對extern的應用,不同的場合應該選擇不同的做法。

  5 問題:extern “C”

  在C++環境下使用C函數的時候,常常會出現編譯器無法找到obj模組中的C函數定義,從而導致連結失敗的情況,應該如何解決這種情況呢?

  答案與分析:

  C++語言在編譯的時候為瞭解決函數的多態問題,會將函數名和參數聯合起來產生一個中間的函數名稱,而C語言則不會,因此會造成連結時找不到對應函數的情況,此時C函數就需要用extern “C”進行連結指定,這告訴編譯器,請保持我的名稱,不要給我產生用於連結的中間函數名。

  下面是一個標準的寫法:

  //在。h檔案的頭上#ifdef __cplusplus #if __cplusplus extern "C"{ #endif #endif /* __cplusplus */…

  //.h檔案結束的地方#ifdef __cplusplus #if __cplusplus } #endif #endif /* __cplusplus */

  補充:extern "C"用法extern是C/C++語言中表明函數和全域變數作用範圍(可見度)的關鍵字創意產品網 .它告訴編譯器,其聲明的函數和變數可以在本模組或其它模組中使用。

  1.對於extern變數來說,僅僅是一個變數的聲明,其並不是在定義分配記憶體空間。如果該變數定義多次,會有串連錯誤2.通常,在模組的標頭檔中對本模組提供給其它模組引用的函數和全域變數以關鍵字extern聲明。也就是說c檔案裡面定義,如果該函數或者變數與開放給外面,則在h檔案中用extern加以聲明。所以外部檔案只用include該h檔案就可以了。而且編譯階段,外面是找不到該函數的,但是不報錯。link階段會從定義模組產生的目標代碼中找到此函數。

  3.與extern對應的關鍵字是static,被它修飾的全域變數和函數只能在本模組中使用。

  被extern "C"修飾的變數和函數是按照C語言方式編譯和串連的;未加extern “C”聲明時的編譯方式

  首先看看C++中對類似C的函數是怎樣編譯的。

  作為一種物件導向的語言,C++支援函數重載,而過程式語言C則不支援。函數被C++編譯後在符號庫中的名字與C語言的不同。例如,假設某個函數的原型為:

  void foo( int x, int y );

  該函數被C編譯器編譯後在符號庫中的名字為_foo,而C++編譯器則會產生像_foo_int_int之類的名字(不同的編譯器可能產生的名字不同,但是都採用了相同的機制,產生的新名字稱為“mangled name”)。

  _foo_int_int這樣的名字包含了函數名、函數參數數量及類型資訊,C++就是靠這種機制來實現函數重載的。例如,在C++中,函數void foo( int x, int y )與void foo( int x, float y )編譯產生的符號是不相同的,後者為_foo_int_float.

  同樣地,C++中的變數除支援局部變數外,還支援類成員變數和全域變數。使用者所編寫程式的類成員變數可能與全域變數同名,我們以"."來區分。而本質上,編譯器在進行編譯時間,與函數的處理相似,也為類中的變數取了一個獨一無二的名字,這個名字與使用者程式中同名的全域變數名字不同。

  未加extern "C"聲明時的串連方式

  假設在C++中,模組A的標頭檔如下:

  // 模組A標頭檔 moduleA.h #ifndef 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這樣的符號!

  加extern "C"聲明後的編譯和串連方式

  加extern "C"聲明後,模組A的標頭檔變為:

  // 模組A標頭檔 moduleA.h #ifndef MODULE_A_H #define MODULE_A_H extern "C" int foo( int x, int y );#endif

  在模組B的實現檔案中仍然調用foo( 2,3 ),其結果是:

  (1)模組A編譯產生foo的目標代碼時,沒有對其名字進行特殊處理,採用了C語言的方式;

  (2)連接器在為模組B的目標代碼尋找foo(2,3)調用時,尋找的是未經修改的符號名_foo.

  如果在模組A中函式宣告了foo為extern "C"類型,而模組B中包含的是extern int foo( int x, int y ) ,則模組B找不到模組A中的函數;反之亦然。

  所以,可以用一句話概括extern “C”這個聲明的真實目的(任何語言中的任何文法特性的誕生都不是隨意而為的,來源於真實世界的需求驅動。我們在思考問題時,不能只停留在這個語言是怎麼做的,還要問一問它為什麼要這麼做,動機是什麼,這樣我們可以更深入地理解許多問題):

  實現C++與C及其它語言的混合編程。

  明白了C++中extern "C"的設立動機,我們下面來具體分析extern "C"通常的提示。

  4.extern "C"的慣用法

  (1)在C++中引用C語言中的函數和變數,在包含C語言標頭檔(假設為cExample.h)時,需進行下列處理:

  extern "C" { #include "cExample.h" }

  而在C語言的標頭檔中,對其外部函數只能指定為extern類型,C語言中不支援extern "C"聲明,在。c檔案中包含了extern"C"時會出現編譯語法錯誤。

  筆者編寫的C++引用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;}

  如果C++調用一個C語言編寫的。DLL時,當包括。DLL的標頭檔或聲明介面函數時,應加extern "C" { }.

  (2)在C中引用C++語言中的函數和變數時,C++的標頭檔需添加extern "C",但是在C語言中不能直接引用聲明了extern"C"的該標頭檔,應該僅將C檔案中將C++中定義的extern "C"函式宣告為extern類型。

  筆者編寫的C引用C++函數例子工程中包含的三個檔案的原始碼如下:

  //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;}

extern及extern “C”用法

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.