extern "C"的引入是为了解决C++函数重载的问题,C++之父在设计C++语言的时候,考虑到对C的兼容,引入了extern "C",使得在C++中能够无误地使用C的库函数(大部分的库函数都是由C编写的)
在编译期间,C和C++为函数生成修饰名的方式是不一样的,这一点可以认为是C++实现函数重载的机制,考虑这样一段C代码:
int fun(int x)
{
return 0;
}
使用 /FAs 选项生成汇编代码,留意fun函数的修饰名:
; 这是使用C编译方式进行编译的
PUBLIC _fun ; _fun是函数fun的修饰名
_TEXT SEGMENT
_x$ = 8
_fun PROC NEAR
; 3 : {
push ebp
mov ebp, esp
; 4 : return x;
mov eax, DWORD PTR _x$[ebp]
; 5 : }
pop ebp
ret 0
_fun ENDP
_TEXT ENDS
END
同样的代码,换成C++的编译方式,汇编代码如下:
PUBLIC ?fun@@YAHH@Z
_TEXT SEGMENT
?fun@@YAHH@Z PROC NEAR ; ?fun@@YAHH@Z 是 fun 函数的修饰名
; 12 : {
push ebp
mov ebp, esp
; 13 : return 0;
xor eax, eax
; 14 : }
pop ebp
ret 0
?fun@@YAHH@Z ENDP ; fun
_TEXT ENDS
END
/* fun.c */
int fun(int x)
{
return x;
}
// test.cpp
#include <stdio.h>
extern int fun(int);
int main(void)
{
printf("%d\n", fun(2));
getchar();
return 0;
}
提示的错误是:
原因是:fun是采用C的编译方式,编译器为其生成的函数修饰名是_fun,而在test.cpp文件中的fun函数采用的是C++编译方式,生成的修饰名是?fun@@YAHH@Z,在链接阶段,由于前后fun生成的修饰名不一致,导致重定向失败,所以就出错了!
而为了在C++中使用C编译方式,才引入了extern "C"技术(其实不光是这样,想想在项目中使用的库函数,大部分都是用C语言编译方式的),现在对上面的test.cpp代码进行改动:
// test.cpp
#include <stdio.h>
extern "C"
{
extern int fun(int);
}
int main(void)
{
printf("%d\n", fun(2));
getchar();
return 0;
}
在extern int fun(int)外加入extern "C"进行声明,就告诉编译器fun函数是按C语言编译方式进行编译的,于是,编译器就为fun函数生成C方式的修饰名,对test.cpp使用/FAs选项,留意一下fun函数的修饰名:
EXTRN _fun:NEAR
_DATA SEGMENT
$SG529 DB '%d', 0aH, 00H
_DATA ENDS
_TEXT SEGMENT
_main PROC NEAR
; 10 : {
push ebp
mov ebp, esp
push ecx
; 11 : printf("%d\n", fun(2));
push 2
call _fun ; 现在fun函数的修饰名变成C方式了!
add esp, 4
push eax
push OFFSET FLAT:$SG529
call _printf
add esp, 8