時常在cpp的代
碼之中看到這樣的代碼:
"cLr:UNPHdGBSD愛好者樂園+f&mVC,~)wyl
#ifdef
__cplusplus
]#r7WE^-zi4RDHextern "C" {BSD愛好者樂園;ZPL2r-_E%?x
#endif
ir8c:N+b2`$Kax
T*V}A%f_.n:U/m//一段代碼BSD愛好者樂園/B4L.mk!JP&H
t1ZE1H5o+~1B1S#ifdef __cplusplusBSD愛好者樂園K;D)H&@]5~
}
!Oj.Q#F5RsK#endif BSD愛好者樂園+ID#RM"Z0x
X
BSD愛好者樂園B)MW,Jhe;{v#P
這樣的代碼到底是什么意思呢,?首先,__cplusplus是cpp中的自定義宏,,那么定義了這個宏的話表示這是一段cpp的代碼,也就是說,,上面的代
碼的含義是:如果這是一段cpp的代碼,,那么加入extern "C"{和}處理其中的代碼。
'G6ertj5KbBSD愛好者樂園x!l(Q
Fu?E
要明白為何使用extern "C",,還得從cpp中對函數(shù)的重載處理開始說起,。在c++中,,為了支持重載機制,在編
譯生成的匯編碼中,,要對函數(shù)的名字進行一些處理,,加入比如函數(shù)的返回類型等等.而在C中,只是簡單的函數(shù)名字而已,,不會加入其他的信息.也就是說:C++
和C對產(chǎn)生的函數(shù)名字的處理是不一樣的.
sUk;G?\n'{D
5q7|D\V 比如下面的一段簡單的函數(shù),,我們看看加入和不加入extern
"C"產(chǎn)生的匯編代碼都有哪些變化:
t#HJIm.W:G
m3Z0s$M:Mxint f(void)BSD愛好者樂園h0K4i+t2L1yx
{
Q Uy)qkreturn 1;BSD愛好者樂園T9Ujn1f
} BSD愛好
者樂園#\C
d_u:l7I)H
BSD愛好者樂園Q-Fw;|)wS
n
^
在加入extern "C"的時候產(chǎn)生的匯編代碼是:
6k~/vq4S
U*m#zhZ$XX:g.file "test.cxx"BSD愛好者樂園"rS_@(UlGo9~ z
.text
Z8_f1Ek#N,ey)\.align 2BSD愛好者樂園bS
Z7[KF
.globl _fBSD愛好者樂園 [(GA
V@U.|
.def _f; .scl 2; .type 32; .endefBSD愛好者樂園e/J?B1K#s| _"\@6s&`0T
_f:
9R?p1q9V1GMpushl %ebpBSD愛好者樂園wBA:W,K@$sL
movl %esp,
%ebpBSD愛好者樂園1Q.tJ#Vu7Q'A3@t
movl
$1,, %eax
V;rmwCa~Mm#Opopl
%ebpBSD愛好者樂園~zrc2T
ret BSD愛好者樂園UF
C9q2}
~.Q^-@7Yoy]al
但是不加入了extern "C"之后
.rn-L}auy:m1~+B
T/At4^*t)c.file "test.cxx"BSD愛好者樂園+T\Xun7ZNJ
.textBSD愛好者樂園}zE,p]7`2|S*H
.align 2BSD愛好者樂園j+l)t;z5OVH
.globl __Z1fvBSD愛好者樂園I"L(L1sw f'g@i
.def
__Z1fv; .scl 2; .type 32; .endef
/iB-L]C$\"Y1?6fG`__Z1fv:
jgqSj3A;orpushl %ebpBSD愛好者樂園
e M0R4R"]6BZM,\'g
movl %esp,, %ebp
XXHoAVmrmovl $1, %eaxBSD
愛好者樂園V
M,iY;t%`
m ~
popl %ebp
0g"J)pU
YjOcR?Bret
z&MW@![X{'~L$@
@!d9u+bt
_~ 兩段匯編代碼同樣都是使用gcc
-S命令產(chǎn)生的,,所有的地方都是一樣的,,唯獨是產(chǎn)生的函數(shù)名,一個是_f,,一個是__Z1fv,。
.D}E:h7OBSD愛好者樂園#wV3m?Q
}k
明白了加入與不加入extern "C"之后對函數(shù)名稱產(chǎn)生的影響,我們繼續(xù)我們的討論:為什么需要使用extern
"C"呢,?C++之父在設(shè)計C++之時,,考慮到當(dāng)時已經(jīng)存在了大量的C代碼,為了支持原來的C代碼和已經(jīng)寫好C庫,,需要在C++中盡可能的支持C,,而
extern "C"就是其中的一個策略。 BSD愛好者樂園4w?*@W
E,?:a6YG)_QM
試想這樣的情況:一個庫文件已經(jīng)用C寫好了而且運行得很良好,,這個時候我們需要使用這
個庫文件,,但是我們需要使用C++來寫這個新的代碼。如果這個代碼使用的是C++的方式鏈接這個C庫文件的話,,那么就會出現(xiàn)鏈接錯誤.我們來看一段代碼:
首先,,我們使用C的處理方式來寫一個函數(shù),也就是說假設(shè)這個函數(shù)當(dāng)時是用C寫成的:
f?T
@E7bV!y0T:DTBSD愛好者樂園@
bH7gVm
//f1.c
-w|ZN T9T3jextern
"C"
'MTlWB{BSD愛好者樂園/dx
_3I?J'P#b
void f1()BSD愛好者樂
園;g"T,r.b(z9_4RX+dv:u*lS
{BSD愛
好者樂園!T0w
]ok-}#u]*]l??
return;BSD愛好者樂園
@^'D${9C+g
\P
}
s]~(s.^y"wucA.S)v}
1E@s4\Q(N'ZyBSD愛好者樂園,y+HR%s-X4u$sY0}:z,k
編譯命令是:gcc -c f1.c -o
f1.o 產(chǎn)生了一個叫f1.o的庫文件,。再寫一段代碼調(diào)用這個f1函數(shù):
$h9Bc-v{QJ2oBSD愛好者樂園#U)uE U/I-M?A7B vs7_
//
test.cxx
+ptz5I*}5~ ok//這個
extern表示f1函數(shù)在別的地方定義,,這樣可以通過BSD愛好者樂園e8X3Jz
]X'J7q:X@ X i1J
//編譯,但是鏈接的時候還是需要BSD愛好者樂園?zI(V_l G
//鏈接上原來的庫文件.
[
v8rj.I]extern void f1();BSD愛好者樂園
Q%x
k\9D"}sd,d
BSD愛好者樂園_$I4`:C~
D
int main()BSD愛好者樂園
c$nzaB&s
{
:c_&N1ZKB`$S!jf1();
c)\j?]
L5dfGs9{#v
4|aQ.U&Kreturn
0;
$Q9IMQ'i?{}
BP0I?ArBSD愛好者樂園&N]-YU!GAEB5_V&n
通過gcc -c test.cxx -o test.o 產(chǎn)生一個叫test.o的文件,。然后,,我們使用gcc test.o
f1.o來鏈接兩個文件,可是出錯了,,錯誤的提示是:BSD愛好者樂園&ri0m
L|7U?V
t*F
~-Y,W [2oVTtest.o(.text
+ 0x1f):test.cxx: undefine reference to 'f1()' BSD愛好者樂園?c8[[`e)r-Yv
BSD
愛好者樂園-M.Gg0@3JR3r){x
也就是說,,在編譯test.cxx的時候編譯器是使用C++的方式來處理
f1()函數(shù)的,但是實際上鏈接的庫文件卻是用C的方式來處理函數(shù)的,,所以就會出現(xiàn)鏈接過不去的錯誤:因為鏈接器找不到函數(shù),。
3I2BWG"u`$kBSD
愛好者樂園L
Lz,U+L?'AL
因此,,為了在C++代碼中調(diào)用用C寫成的庫文件,就需要用extern
"C"來告訴編譯器:這是一個用C寫成的庫文件,,請用C的方式來鏈接它們,。BSD愛好者樂園
ro&E)B8E5x
BSD愛好者樂園B
_6lQ3@:E/K!]{1D
比如,現(xiàn)在我們有了一個C庫文件,,它的頭文件是f.h,,產(chǎn)生的lib文件是f.lib,那么
我們?nèi)绻贑++中使用這個庫文件,,我們需要這樣寫:BSD愛好者樂園,nGv
['B"idx'Iy}
extern "C"
MEf5x*H{BSD愛好者樂園&j:M3o%tk9O8u3yw?W
#i
nclude "f.h"
S;C0IUL[9p3L}
KT"XG%f
@,XBSD愛好者樂園/u mZ`%Z
回到上
面的問題,,如果要改正鏈接錯誤,我們需要這樣子改寫test.cxx:BSD愛好者樂園
O8U&GfL}$[
y5Wp(M*|extern
"C"
+@,@%a:{;wl{
(qw'Fo7plGextern void f1();
#_3Xh`D_2R}BSD愛好者樂園3x@Cj'GZ c
BSD
愛好者樂園
Y&~t\MZ(O
int main()BSD愛好者
樂園c:\f?sSL!~3Bt
{
J
W*pI:A1u$ef1();
Nr @
H-`%Y&g
\5I
no,x1Kreturn 0;
[
jHf\:Lk J o} BSD愛好者樂園5rv7deB
E
O(HLw:X
BSD愛好者樂園9SB)h
S9X3n W$ct
重新編譯并且鏈接就可以過去了.BSD愛好
者樂園0g,j:^ek_
s$B*o
O9`;``9v9^3p 總結(jié)BSD愛好者樂園T]'O]7tvz
BSD愛好者樂園epE9D~Z?
C和C++對函數(shù)的處理方式是不
同的.extern "C"是使C++能夠調(diào)用C寫作的庫文件的一個手段,,如果要對編譯器提示使用C的方式來處理函數(shù)的話,,那么就要使用extern
"C"來說明。
A lI2m?)H
%a;h1]{q^,ZBSD
愛好者樂園ob_(I}Xv)K
gc2r
S!pJi
o
Gi?B/H;Z+L0b~G
L
hh,k(aNx_作者:宋寶華 e-mail:[email protected] 出處:太平洋電腦網(wǎng)BSD愛好者樂園.h_ \9\'Q[
g'tF~1Rj(\^L1.引言
*?}!G V!c;Cs!JBSD愛好者樂園7u0Y)zGb7yFO"e
C++語言的創(chuàng)建初衷是“a better
C”,,但是這并不意味著C++中類似C語言的全局變量和函數(shù)所采用的編譯和連接方式與C語言完全相
同,。作為一種欲與C兼容的語言,C++保留了一部分過程式語言的特點(被世人稱為“不徹底地面向?qū)ο?#8221;),,因而它可以定義不屬于任何類的全局變量和函數(shù),。
但是,C++畢竟是一種面向?qū)ο蟮某绦蛟O(shè)計語言,,為了支持函數(shù)的重載,,C++對全局函數(shù)的處理方式與C有明顯的不同。BSD愛好者樂園%SRujz4F6H
BSD愛好者樂園wZ.`v!z[
2.從標(biāo)準(zhǔn)頭文件說起
^
f oc:n3`G0@
qE)nqb0h9|oy某
企業(yè)曾經(jīng)給出如下的一道面試題:BSD愛好者樂園qJ@*M*j/X
e&?
,@6E6gn8s S面試題
7Yza7]DR.vbBSD愛好者樂園Kr+cQ m%pn
為什么標(biāo)準(zhǔn)頭文件都有類似以下的結(jié)構(gòu),?BSD愛好者樂園3w#io9R
C'X,Vs3wG
BSD愛好者樂園
{?d!InCX?xN
#ifndef __INCvxWorkshBSD愛好者樂園%y-Y\I6m3U:a
v%CI[)dZ
#define __INCvxWorksh
w3TLX_
dSK!e~ #ifdef __cplusplus
/tOb*Bn7T/qHBSD愛好者樂園x)wOo&ow(Vo4L
extern "C" {BSD愛好者樂園FIG
Jf`2C
DHj`_sbl
#endifBSD愛好者樂園)OA"OtR'P8Cl
~ p0KWI?8v'j~ /*...*/
}P]*D4x#uJ
C` \Q"x)~
^ #ifdef __cplusplus
l%y@`!_.H%bb
o
^2d JhX }BSD愛好者樂園9@MFJ"|
,T*A.vV[+GV6tR| #endifBSD愛好者樂園H5dXx
EoE$e]
BSD愛好者樂園.EP1nH
qJ4q0A'D
Z$O
#endif /* __INCvxWorksh */
:Q
vZ`*D5M,r
4Et4Qav(N6J&q分
析
1C6E,oGLUH ?c
,lw.gkp9^H?^:WB顯然,,頭文件中的編譯宏“#ifndef
__INCvxWorksh、#define __INCvxWorksh,、#endif” 的作用是防止該頭文件被重復(fù)引用,。
IZ!Q#r*t;m-N
c,O
\S/lA1h0xI那么
"i z#YZHC
h
8wS7Xkn8| #ifdef
__cplusplusBSD愛好者樂園DT6Y*FR9y
o5l
BSD愛好者樂園mX0]2Nkt2h#?W u
extern "C" {
#}9^(~5W^]BSD愛好者樂園Gc ^[email protected]Gp M
#endif
,dA?Lt)w6WdY`#Mq
F a8{]y,S
K #ifdef __cplusplusBSD愛好者樂園`
c(X9j.Fia
BSD愛好者樂園m
\_?C Nl(i
}
d{[9ceE
,t_1p:ZT3hZ #endifBSD愛好者樂園:@F.`[e\
k#ICK&t
w
M
e9M`;k的作用又是什么呢?我們將在下文一一道來,。
/r|1xF|,d'`*]BSD愛好者樂園;K3w&d%C"pi2NRy:x
3.深層揭密
extern "C"
:gr7^(yGCzP!KGC
H-M6G!x6fextern "C"
包含雙重含義,,從字面上即可得到:首先,被它修飾的目標(biāo)是“extern”的,;其次,,被它修飾的目標(biāo)是“C”的。讓我們來詳細解讀這兩重含義,。BSD愛好者樂園stDE9L$JK
BSD愛好者樂園kPrWa1k
EBc6Y
(1) 被extern "C"限定的函數(shù)或變量是extern類型的,;
aot a5XBSD
愛好者樂園F-G"B6ag
b
extern是C/C++語言中表明函數(shù)和全局變量作用范圍(可見性)的關(guān)鍵字,該關(guān)鍵字告訴編譯器,其聲明的函數(shù)和變量可以在本
模塊或其它模塊中使用,。記住,下列語句:
Q0zg?^A:g9U!hF
F.Uk6To{?'B7Yextern int a;BSD愛好者樂園|)^]'w5|
4P_3?g:t[M*NtM僅僅是一個變量的聲明,,其并不是在定義變量a,,
并未為a分配內(nèi)存空間。
變量a在所有模塊中作為一種全局變量只能被定義一次,,否則會出現(xiàn)連接錯誤,。
O.gbO?u#e-aBSD愛好者樂園`0cq
]#R/^
通常,在模塊的頭文件中對本模塊提供給其它模塊引用的函數(shù)和全局變量以關(guān)鍵字extern聲明,。例如,,如果模塊B欲引用該
模塊A中定義的全局變量和函數(shù)時只需包含模塊A的頭文件即可。這樣,,模塊B中調(diào)用模塊A中的函數(shù)時,,在編譯階段,模塊B雖然找不到該函數(shù),,但是并不會報
錯,;它會在連接階段中從模塊 A編譯生成的目標(biāo)代碼中找到此函數(shù)。BSD愛好者樂園3V
n+Pw7E8J
jYp1`9I#r
\qww'vh與
extern對應(yīng)的關(guān)鍵字是static,,被它修飾的全局變量和函數(shù)只能在本模塊中使用,。因此,一個函數(shù)或變量只可能被本模塊使用時,,其不可能被
extern “C”修飾,。
2X*@#Pvry!u?:l
(u*D
R9b%K#m(2) 被extern "C"修飾的變量和函數(shù)是按照C語言方式編譯和連接的;BSD愛好者樂園%O}2pb6Mf
BSD愛好者樂園
P/gFvP!@
未加extern “C”聲明時的編譯方式
6UTR3|CBSD愛好者樂園S
z0e1v&X2`g
N
首先看看C++中對類似C的函數(shù)是怎樣編譯的,。BSD愛好者樂園
9z(iB8GgZ1p!Ui
GU0{8`4mk/^H1@I作
為一種面向?qū)ο蟮恼Z言,,C++支持函數(shù)重載,而過程式語言C則不支持,。函數(shù)被C++編譯后在符號庫中的名字與C語言的不同,。例如,假設(shè)某個函數(shù)的原型為:
A^$n3ma$l5|BSD愛好者樂園 W|'dT7q
void foo( int x, int y );BSD愛好者樂園&Eik%w+}p~s%t
BSD愛好者樂園a
Q&F5]$PN*z9O1u
該函數(shù)被C編譯器編譯后在符號庫中的名字為_foo,,而C++編譯器則會產(chǎn)生像
_foo_int_int之類的名字(不同的編譯器可能生成的名字不同,,但是都采用了相同的機制,生成的新名字稱為“mangled
name”),。_foo_int_int這樣的名字包含了函數(shù)名,、函數(shù)參數(shù)數(shù)量及類型信息,C++就是靠這種機制來實現(xiàn)函數(shù)重載的,。例如,,在C++中,函
數(shù)void foo( int x, int y )與void foo( int x, float y
)編譯生成的符號是不相同的,后者為_foo_int_float,。
cG
s(O,e5u p^{[
@dNW3~
B9rR7e同樣地,,C++中的變量除支持局部變量外,還支持類成員變量和全局變量,。用戶所編寫程序的類成員變量可能與全局變量同名,,我
們以"."來區(qū)分。而本質(zhì)上,,編譯器在進行編譯時,,與函數(shù)的處理相似,也為類中的變量取了一個獨一無二的名字,,這個名字與用戶程序中同名的全局變量名字不
同,。
-@;H"G3|:W+H Q E
}$q?^^wIr%^6A$_未加extern "C"聲明時的連接方式BSD愛好者樂園?|!fF0Jckjy
BSD愛好者樂園2LoEu?B,U7M
假設(shè)在C++中,模塊A的頭文件如
下:
-~c*t)j MS@PLBSD愛好者樂園vv0],V!irm
~q
// 模塊A頭文件 moduleA.hBSD愛好者樂園N
gGpl%@`3@
BSD愛好者樂園:h7FZ
B4p7mM
#ifndef MODULE_A_H
4yhr%]
eY&M!l.y
1c,?C#y
`"SeC1q[A@ #define MODULE_A_H
1o
stX$DLTUBSD愛好者樂園w}mrP3q-H
int foo( int x, int y );BSD愛好者樂園9i(UJ!e'[
BSD愛好者樂園M5dOns(l0E
#endif
;W#]?^ si.q
%K+GMD"z"BW!S0G在模塊B中引用該函數(shù):BSD
愛好者樂園6[ Sj0Gd+J
BSD愛好者樂園.]+zP
~I0rho
W%W2j
// 模塊B實現(xiàn)文件 moduleB.cppBSD愛好者
樂園%n'K+m(J$r
RA;J
K2h9[,T,S#i
nclude "moduleA.h"
&A]&y_
d$L&`F
,PaF-r&tw|[
{foo(2,3);
)QV9p1r]E3D q
VZv#JC,_0K?AV5v實際上,,在連接階段,,連接器會從模塊A生成的
目標(biāo)文件moduleA.obj中尋找_foo_int_int這樣的符號!
$D9eo
`+T"PBSD愛好者樂園(xQ%a2]5q?q6v
加extern
"C"聲明后的編譯和連接方式BSD愛好者樂園
P&c?9l3QO&[
D9K_"@%w9U:w^
a加extern "C"聲明后,,模塊A的頭文件變?yōu)椋?/p>
ztw
XA|T2GBSD愛好者樂園b9ECC^-d)m
//
模塊A頭文件 moduleA.hBSD愛好者樂園V8@2s;~TI
?)BME9PFvJJ#ifndef MODULE_A_H
^7m"I(TZ&vB5A&^BSD愛好者樂園F-Om!y&{*gf
#define MODULE_A_HBSD愛好者樂園^m
GlVxmW"TNv
BSD愛好者樂園'Qpj
{5S0t]Z
z
extern "C" int foo( int x, int y );BSD愛好者樂園1v.m&C8N/U"X$_-|1~
+P;L$e.OPHZ#endifBSD愛好者樂園
mTmc5Rd#Z#z6@
BSD愛好者樂園d[B
Sn,}
在模塊B的實現(xiàn)文件中仍然調(diào)用foo( 2,3 ),,其結(jié)果是:
#aO1T)\/\BSD愛好者樂園.Z8^x
c?t??!Qq
(1)模塊A編譯生成foo的目標(biāo)代碼時,沒有對其名字進行特殊處理,,采用了C語言的方式,;BSD愛好者樂園1s5{Z-y3m6\:^
f}6^;^(pXO(2)連接器在為模塊B的目標(biāo)代碼尋找foo(2,3)調(diào)用
時,尋找的是未經(jīng)修改的符號名_foo,。
B\5N3GAfe5jBSD愛好者樂園'D6a5o?~}vU
如果在模塊A中函數(shù)聲明了foo為
extern "C"類型,,而模塊B中包含的是extern int foo( int x, int y )
,則模塊B找不到模塊A中的函數(shù),;反之亦然,。BSD愛好者樂園#?4^Fp'{ c-U
%\V2M*\X lLN所以,可以用一句話概括extern
“C”這個聲明的真實目的(任何語言中的任何語法特性的誕生都不是隨意而為的,,來源于真實世界的需求驅(qū)動,。我們在思考問題時,不能只停留在這個語言是怎么
做的,,還要問一問它為什么要這么做,,動機是什么,這樣我們可以更深入地理解許多問題):
_#Rw&K'g @2s,WOE
3e#z)k"J)s+Lawx{實
現(xiàn)C++與C及其它語言的混合編程,。
k3Jz*{/GaBSD愛好者樂園m$p?~-ML
明白了C++中extern
"C"的設(shè)立動機,,我們下面來具體分析extern "C"通常的使用技巧。BSD愛好者樂
園_ G%Pp$B
BSD愛好者樂園/_9p
c#`5EM$O
4.extern "C"的慣用法BSD愛好者樂園
\1e,|%P,H?{\
BSD愛好者樂園8{?qjH
\Z.JZ
(1)在C++中引用C語言中的函數(shù)和變量,,在包含C語言頭文件(假設(shè)為cExample.h)時,,需進行下列處理:
f1a
M;]N'\'Bg
Kr$r%v%q }A-sextern
"C"BSD愛好者樂園0^$hN
vwY
U
*M/l5i6|b9fe2q{
N.dj3nA6BdBSD愛好者樂園.T&Gb3DS&~PYz
#i nclude
"cExample.h"
3U
OJ8a?^Q1bRk5\p
mk%IR
aPkk}BSD愛好者樂園)kXT I}{
BSD愛好者樂園|V
g9?6k6r
而在C語言的頭文件中,,對其外部函數(shù)只能指定為extern類型,C語言中不支持extern
"C"聲明,,在.c文件中包含了extern "C"時會出現(xiàn)編譯語法錯誤,。
tfa8zw/Xl
,\v
WR?q!f5O筆者編寫的C++引用C函數(shù)例子工程中包含的三個文件的源代碼如下:BSD愛好者樂園qG WFw0a7I{9z
BSD
愛好者樂園"og;j"o+n/Z5J6]0@
/* c語言頭文件:cExample.h */BSD愛好者樂園.nJppK&U&U]$Z-U|?U
t4]7C3Af/tG;uk#ifndef C_EXAMPLE_HBSD愛好者樂園0sd9x/pa
BSD愛好者樂園1NrxH7v
#define C_EXAMPLE_HBSD愛好者樂園NQ1O vu[f
Q
BSD愛好者樂園!i;jvGJ#m,R4i
extern
int add(int x,int y);
'ge5y8K`W3zGBSD愛好者樂園f*xN
l2z]TQ
#endif
UG]
?
D H'oBSD愛好者樂園B'zs1{"U4C:rn,|8]~
/*
c語言實現(xiàn)文件:cExample.c */BSD愛好者樂園oC)_)xjP
B \@}D.k
BSD愛好者樂園3n.C
c-\%h#G%}%n
#i nclude "cExample.h"BSD
愛好者樂園8D*FU6~~5R3F4P,}
4k8\C4|"Xs_&`int
add( int x, int y )
Q0Y!];k@$Q1k7niF?p
iBSD愛好者樂園;n"?b%[:l[(G{J
{BSD愛好者樂園f&W:F3D4{[-ei1?m8o
8_2t6G'Fn_1X%q-Jr return x + y;
z9N"c3n"eNuA?;MqrBSD愛好者樂園@&D?1z4j
}BSD愛好者樂園J]4ZS6j/fJE&R
XZ8}@Q// c++實現(xiàn)文件,調(diào)用add:cppFile.cppBSD愛好者樂園$M0axe;SvQ3?#`
BSD愛好者樂園o H)k0P)S.o
extern "C"
-Y;m0piRZ-W+sBSD愛好者樂園0y:M$g'T\W:}
{
kK"uNAL0G)H
3D5fN7X+B7vz*Q#i nclude "cExample.h"
e[W5JF9P2fvw1g%qBSD愛好者樂園6["YtGI(`K4Zw;X/_
}
2Hl9U5TM/p`j`dv
%^x2qE%p
Ivint main(int argc, char* argv[])
r'fo ga.Eg,rgBSD愛好者樂園2l
@Dr^7L"kSA.mS
{BSD愛好者樂園ZO
J5I"R;G {
BSD愛好者樂園U1q%P`;V*Gy
WCBuPz,g
add(2,3);
6fq1^n%}BSD愛好者樂園[xNX9wqB
X
return 0;
4j
g%Rv/[7Y_
oB
TR;m1w}BSD愛好者樂園FWV]}-wEz
Sw'O$ofrg如果C++調(diào)用一個C語言編寫的.DLL時,,當(dāng)包
括.DLL的頭文件或聲明接口函數(shù)時,,應(yīng)加extern "C" { }。
-gx8}4x){W]BSD愛好者樂園+HF6_3}T
(2)在C中引用C++語言中的函數(shù)和變量
時,,C++的頭文件需添加extern "C",但是在C語言中不能直接引用聲明了extern
"C"的該頭文件,,應(yīng)該僅將C文件中將C++中定義的extern "C"函數(shù)聲明為extern類型,。
.D!r0PI;\*k1u
b4kL d5`Z?O筆者編寫的C引用C++函數(shù)例子工程中包含的三個文件的源代碼如下:BSD愛好者樂園/x(n0e{EG#@
@$P#Hi@Zt+a//C++頭文件 cppExample.hBSD愛好者樂園"VYUz,s*X)R5R
E0X|q8R+L.tf#ifndef CPP_EXAMPLE_H
5Y8Y0]^9C#k,Em
/b|%Fl6O9OPx#define CPP_EXAMPLE_HBSD愛好者樂園-itD@E![E(C
$C7}[k_I
Miextern "C" int add( int x, int y );BSD愛好者樂園6k7WH
VR
UNOG%B8\x#endif
(AFV&?9}#X
N)t3^-^FRa3O//C++實現(xiàn)文件 cppExample.cpp
bW&C%^H'N@;PBSD愛好者樂園5w8c@2\/]Rt
#i nclude "cppExample.h"BSD愛好者樂園 J?_pk4x
R?Y2j*z?`int add( int x, int y )
3Fgb`QBSD
愛好者樂園6z%y"Ta@nN?v}T
{
nX8JxUr?Z&uBSD愛好者樂園ES!VP&n!gGO:eXr4j
return x + y;
m.Y$P;pb5VLXf!IBSD愛好者樂園J3s][Tls
}BSD愛好者樂園 r*P
KMoNen
Tj E;DEl/*
C實現(xiàn)文件 cFile.c
5w!V,Su)n(W'q/N
}Q0w2?"UOU%x/* 這樣會編譯出錯:#i nclude
"cExample.h" */
#f,{-NOU
x6WBSD愛好者樂園9u&kw6Wu,f@G/c9L
extern
int add( int x, int y );
$uB-{-dN[cUe`BSD愛好者樂園*~!q|V3}Gf
int main( int
argc, char* argv[] )
$[n_ OW-IBSD愛好者樂園0~[OyD
{
YR8DqG"H%MP,J$zQ#D
zY,nJ-T add( 2, 3 ); BSD愛好者樂園1j+x,n+O9b
BSD愛好者樂園}4ELA5emY
return 0;BSD愛好者樂園Lf/B%jM.t
BSD愛好者樂園&[a/uV2^E"g.q!p5O
}
~"~G(fk1a osW