| 導購 | 订阅 | 在线投稿
分享
 
 
當前位置: 王朝網路 >> c/c++ >> C++中extern 「C」含義深層探索
 

C++中extern 「C」含義深層探索

2008-06-01 02:04:57  編輯來源:互聯網  简体版  手機版  評論  字體: ||
 
 
  1.引言

  C++語言的創建初衷是「a better C」,但是這並不意味著C++中類似C語言的全局變量和函數所采用的編譯和連接方式與C語言完全相同。

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  作爲一種欲與C兼容的語言,C++保留了一部分過程式語言的特點(被世人稱爲「不徹底地面向對象」),因而它可以定義不屬于任何類的全局變量和函數。但是,C++究竟是一種面向對象的程序設計語言,爲了支持函數的重載,C++對全局函數的處理方式與C有明顯的不同。2.從標准頭文件說起

  某企業曾經給出如下的一道面試題:

  面試題

  爲什麽標准頭文件都有類似以下的結構?

  #ifndef __INCvxWorksh

  #define __INCvxWorksh

  #ifdef __cplusplus

  extern "C" {

  #endif

  /*...*/

  #ifdef __cplusplus

  }

  #endif

  #endif /* __INCvxWorksh */

  分析

  顯然,頭文件中的編譯宏「#ifndef __INCvxWorksh、#define __INCvxWorksh、#endif」 的作用是防止該頭文件被重複引用。

  那麽

  #ifdef __cplusplus

  extern "C" {

  #endif

  #ifdef __cplusplus

  }

  #endif

  的作用又是什麽呢?我們將在下文一一道來。

  

C++中extern 「C」含義深層探索
更多內容請看C/C++技術專題專題,或

  3.深層揭密extern "C"

  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,被它修飾的全局變量和函數只能在本模塊中使用。因此,一個函數或變量只可能被本模塊使用時,其不可能被extern 「C」修飾。

  被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/C++技術專題專題,或

  同樣地,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"通常的使用技巧。

  

C++中extern 「C」含義深層探索
更多內容請看C/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;

  }

  假如深入理解了第3節中所闡述的extern "C"在編譯和連接階段發揮的作用,就能真正理解本節所闡述的從C++引用C函數和C引用C++函數的慣用法。對第4節給出的示例代碼,需要非凡留意各個細節。

  歡迎與作者聯系溝通。聯系方式:

  Email: 21cnbao@21cn.com

  MSN: barrysong80@hotmail.com

C++中extern 「C」含義深層探索
更多內容請看C/C++技術專題專題,或
 
 
 
上一篇《C/C++編程新手錯誤語錄》
下一篇《C++實現用掌上電腦遙控電視》
 
 
 
 
 
 
日版寵物情人插曲《Winding Road》歌詞

日版寵物情人2017的插曲,很帶節奏感,日語的,女生唱的。 最後聽見是在第8集的時候女主手割傷了,然後男主用嘴幫她吸了一下,插曲就出來了。 歌手:Def...

兄弟共妻,我成了他們夜裏的美食

老鍾家的兩個兒子很特別,就是跟其他的人不太一樣,魔一般的執著。兄弟倆都到了要結婚的年齡了,不管自家老爹怎麽磨破嘴皮子,兄弟倆說不娶就不娶,老父母爲兄弟兩操碎了心...

如何磨出破洞牛仔褲?牛仔褲怎麽剪破洞?

把牛仔褲磨出有線的破洞 1、具體工具就是磨腳石,下面墊一個硬物,然後用磨腳石一直磨一直磨,到把那塊磨薄了,用手撕開就好了。出來的洞啊很自然的。需要貓須的話調幾...

我就是掃描下圖得到了敬業福和愛國福

先來看下敬業福和愛國福 今年春節,支付寶再次推出了“五福紅包”活動,表示要“把欠大家的敬業福都還給大家”。 今天該活動正式啓動,和去年一樣,需要收集“五福”...

冰箱異味産生的原因和臭味去除的方法

有時候我們打開冰箱就會聞到一股異味,冰箱裏的這種異味是因爲一些物質發出的氣味的混合體,聞起來讓人惡心。 産生這些異味的主要原因有以下幾點。 1、很多人有這種習...

《極品家丁》1-31集大結局分集劇情介紹

簡介 《極品家丁》講述了現代白領林晚榮無意回到古代金陵,並追隨蕭二小姐化名“林三”進入蕭府,不料卻陰差陽錯上演了一出低級家丁拼搏上位的“林三升職記”。...

李溪芮《極品家丁》片尾曲《你就是我最愛的寶寶》歌詞

你就是我最愛的寶寶 - 李溪芮 (電視劇《極品家丁》片尾曲) 作詞:常馨內 作曲:常馨內 你的眉 又鬼馬的挑 你的嘴 又壞壞的笑 上一秒吵鬧 下...

烏梅的功效與作用以及烏梅的食用禁忌有哪些?

烏梅,又稱春梅,中醫認爲,烏梅味酸,性溫,無毒,具有安心、除熱、下氣、祛痰、止渴調中、殺蟲的功效,治肢體痛、肺痨病。烏梅泡水喝能治傷寒煩熱、止吐瀉,與幹姜一起制...

什麽是脂肪粒?如何消除臉部脂肪粒?

什麽是脂肪粒 在我們的臉上總會長一個個像脂肪的小顆粒,弄也弄不掉,而且顔色還是白白的。它既不是粉刺也不是其他的任何痘痘,它就是脂肪粒。 脂肪粒雖然也是由油脂...

網絡安全治理:國家安全保障的主要方向是打擊犯罪,而不是處置和懲罰受害者

來源:中國青年報 新的攻擊方法不斷湧現,黑客幾乎永遠占據網絡攻擊的上風,我們不可能通過技術手段杜絕網絡攻擊。國家安全保障的主要方向是打擊犯罪,而不是處置和懲罰...

河南夫妻在溫嶺網絡直播“造人”內容涉黃被刑事拘留

夫妻網絡直播“造人”爆紅   1月9日,溫嶺城北派出所接到南京警方的協查通告,他們近期打掉了一個涉黃直播APP平台。而根據掌握的線索,其中有一對涉案的夫妻主播...

如何防止牆紙老化?牆紙變舊變黃怎麽辦?

如何防止牆紙老化? (1)選擇透氣性好的牆紙 市場上牆紙的材質分無紡布的、木纖維的、PVC的、玻璃纖維基材的、布面的等,相對而言,PVC材質的牆紙最不透氣...

鮮肌之謎非日本生産VS鮮肌之謎假日貨是謠言

觀點一:破日本銷售量的“鮮肌之謎” 非日本生産 近一段時間,淘寶上架了一款名爲“鮮肌之謎的” 鲑魚卵巢美容液,號稱是最近日本的一款推出的全新護膚品,産品本身所...

中國最美古詩詞精選摘抄

系腰裙(北宋詞人 張先) 惜霜蟾照夜雲天,朦胧影、畫勾闌。人情縱似長情月,算一年年。又能得、幾番圓。 欲寄西江題葉字,流不到、五亭前。東池始有荷新綠,尚小如...

關于女人的經典語句

關于女人的經典語句1、【做一個獨立的女人】 思想獨立:有主見、有自己的人生觀、價值觀。有上進心,永遠不放棄自己的理想,做一份自己喜愛的事業,擁有快樂和成就...

未來我們可以和性愛機器人結婚嗎?

你想體驗機器人性愛嗎?你想和性愛機器人結婚嗎?如果你想,機器人有拒絕你的權利嗎? 近日,第二屆“國際人類-機器人性愛研討會”大會在倫敦金史密斯大學落下帷幕。而...

全球最變態的十個地方

10.土耳其地下洞穴城市 變態指數:★★☆☆☆ 這是土耳其卡帕多西亞的一個著名景點,傳說是當年基督教徒們爲了躲避戰爭而在此修建。裏面曾住著20000人,...

科學家稱,人類死亡後意識將在另外一個宇宙中繼續存活

據英國《每日快報》報道,一位科學家兼理論家Robert Lanza博士宣稱,世界上並不存在人類死亡,死亡的只是身體。他認爲我們的意識借助我們體內的能量生存,而且...

《屏裏狐》片頭曲《我愛狐狸精》歌詞是什麽?

《我愛狐狸精》 - 劉馨棋   (電視劇《屏裏狐》主題曲)   作詞:金十三&李旦   作曲:劉嘉   狐狸精 狐狸仙   千年修...

 
 
 
  1.引言   C++語言的創建初衷是「a better C」,但是這並不意味著C++中類似C語言的全局變量和函數所采用的編譯和連接方式與C語言完全相同。 作爲一種欲與C兼容的語言,C++保留了一部分過程式語言的特點(被世人稱爲「不徹底地面向對象」),因而它可以定義不屬于任何類的全局變量和函數。但是,C++究竟是一種面向對象的程序設計語言,爲了支持函數的重載,C++對全局函數的處理方式與C有明顯的不同。  2.從標准頭文件說起   某企業曾經給出如下的一道面試題:   面試題   爲什麽標准頭文件都有類似以下的結構? #ifndef __INCvxWorksh #define __INCvxWorksh #ifdef __cplusplus extern "C" { #endif /*...*/ #ifdef __cplusplus } #endif #endif /* __INCvxWorksh */   分析   顯然,頭文件中的編譯宏「#ifndef __INCvxWorksh、#define __INCvxWorksh、#endif」 的作用是防止該頭文件被重複引用。   那麽 #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus } #endif   的作用又是什麽呢?我們將在下文一一道來。 [url=/bbs/detail_1785329.html][img]http://image.wangchao.net.cn/it/1323423860572.gif[/img][/url] 更多內容請看C/C++技術專題專題,或   3.深層揭密extern "C"   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,被它修飾的全局變量和函數只能在本模塊中使用。因此,一個函數或變量只可能被本模塊使用時,其不可能被extern 「C」修飾。   被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。 [url=/bbs/detail_1785329.html][img]http://image.wangchao.net.cn/it/1323423860609.gif[/img][/url] 更多內容請看C/C++技術專題專題,或   同樣地,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"通常的使用技巧。 [url=/bbs/detail_1785329.html][img]http://image.wangchao.net.cn/it/1323423860653.gif[/img][/url] 更多內容請看C/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; }   假如深入理解了第3節中所闡述的extern "C"在編譯和連接階段發揮的作用,就能真正理解本節所闡述的從C++引用C函數和C引用C++函數的慣用法。對第4節給出的示例代碼,需要非凡留意各個細節。   歡迎與作者聯系溝通。聯系方式:   Email: 21cnbao@21cn.com   MSN: barrysong80@hotmail.com [url=/bbs/detail_1785329.html][img]http://image.wangchao.net.cn/it/1323423860694.gif[/img][/url] 更多內容請看C/C++技術專題專題,或
󰈣󰈤
 
 
 
  免責聲明:本文僅代表作者個人觀點,與王朝網路無關。王朝網路登載此文出於傳遞更多信息之目的,並不意味著贊同其觀點或證實其描述,其原創性以及文中陳述文字和內容未經本站證實,對本文以及其中全部或者部分內容、文字的真實性、完整性、及時性本站不作任何保證或承諾,請讀者僅作參考,並請自行核實相關內容。
 
 
陽光靓麗的模特兒(8)
陽光靓麗的模特兒(7)
陽光靓麗的模特兒(6)
陽光靓麗的模特兒(5)
秋-印象
德慶盤龍峽 一
松江印象之三
雲之南(寬幅)
 
>>返回首頁<<
 
 
 
 熱帖排行
 
 
 
 
© 2005- 王朝網路 版權所有