标签:
参考:
http://www.cnblogs.com/rollenholt/archive/2012/03/20/2409046.html
被extern "C"修饰的变量和函数是按照C语言方式编译和连接的,实现C++与C的混合编程。
下面做几个实验来理解:
C++和C编译时对函数名的处理
下面是一个C++文件, a.cpp
void func1(void)
{}
void func2(int a)
{}
void func3(int a, int b)
{}
int func4(void)
{}
int func5(int a)
{}
int func6(int a, int b)
{}
int main(int argc, const char *argv[])
{
func1();
func2(1);
func3(1, 2);
func4();
func5(1);
func6(1, 2);
return 0;
}
使用命令 g++ -S a.cpp 编译这个文件,得到编译后得到的汇编文件 a.s,摘录部分内容如下:
1 .LFB1026:
2 .cfi_startproc
3 pushq %rbp
4 .cfi_def_cfa_offset 16
5 .cfi_offset 6, -16
6 movq %rsp, %rbp
7 .cfi_def_cfa_register 6
8 subq $16, %rsp
9 movl %edi, -4(%rbp)
10 movq %rsi, -16(%rbp)
11 call _Z5func1v
12 movl $1, %edi
13 call _Z5func2i
14 movl $2, %esi
15 movl $1, %edi
16 call _Z5func3ii
17 call _Z5func4v
18 movl $1, %edi
19 call _Z5func5i
20 movl $2, %esi
21 movl $1, %edi
22 call _Z5func6ii
23 movl $0, %eax
24 leave
25 .cfi_def_cfa 7, 8
26 ret
27 .cfi_endproc
28 .LFE1026:
可以看到,将函数名分别进行了如下处理:
void func1(void) ---> _Z5func1v
void func2(int a) ---> _Z5func2i
void func3(int a, int b) ---> _Z5func3ii
int func4(void) ---> _Z5func4v
int func5(int a) ---> _Z5func5i
int func6(int a, int b) ---> _Z5func6ii
可以看到,将来参数类型会和函数名结合,从而产生新的标示,与返回值的类型没有关系。这就解释了C++允许函数重载的原因,并且知道了为什么仅返回值类型不同不能认为是重载的原因。
还是这个文件,我们重命名为 b.c,然后使用命令 gcc -S b.c,得到汇编文件 b.s,摘录部分内容如下:
main:
.LFB6:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl %edi, -4(%rbp)
movq %rsi, -16(%rbp)
call func1
movl $1, %edi
call func2
movl $2, %esi
movl $1, %edi
call func3
call func4
movl $1, %edi
call func5
movl $2, %esi
movl $1, %edi
call func6
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
可以看到,在编译过程中,函数的名称并没有改变,这也就解释了C语言为什么不支持函数的重载。
那么,既然C和C++在编译时对函数名的处理不同,那么如何实现C和C++的混合编程呢?即在C中调用C++的函数,在C++中调用C的函数。
先看一下现象:
a.cpp
int main(int argc, const char *argv[])
{
func1();
return 0;
}
使用命令 g++ -c a.cpp,出现如下错误:
a.cpp: In function ‘int main(int, const char**)’:
a.cpp:3:8: error: ‘func1’ was not declared in this scope
func1();
^
原因是我们没有声明func1这个函数,我发现,如果是在C语言中,不声明并不会导致编译错误,原因其实很简单,在C++中,编译的时候给函数设置新的标示符的时候要用到函数的参数类型,如果不声明,编译器无法获得func1的参数类型信息,从而编译出错。而在C语言中,编译过程中函数的标识符就是函数名,不考虑参数信息,也就不会出错。
修改a.cpp如下:
extern func1(void);
int main(int argc, const char *argv[])
{
func1();
return 0;
}
相应的汇编部分内容如下:
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl %edi, -4(%rbp)
movq %rsi, -16(%rbp)
call _Z5func1v
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
b.c
void func1(void)
{}
使用如下命令编译: gcc -c b.c
相应的汇编文件如下:
.file "b.c"
.text
.globl func1
.type func1, @function
func1:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
然后使用命令 g++ a.o b.o 链接,提示如下错误:
a.o: In function `main‘:
a.cpp:(.text+0x10): undefined reference to `func1()‘
collect2: error: ld returned 1 exit status
原因是, 在链接时,由于找不到_Z5func1v导致编译失败,解决办法如下:
修改a.cpp
extern "C" void func1(void);
int main(int argc, const char *argv[])
{
func1();
return 0;
}
我们看一下得到的汇编文件(g++ -S a.cpp):
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl %edi, -4(%rbp)
movq %rsi, -16(%rbp)
call func1
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
可以看到,标识符已经从_Z5func1v变成了func1,即从C++的编译方式变成了C的编译方式,这样在链接时就不会出错了。
那么如果是在C语言中调用C++的函数,结果如何呢?
a.c
int main(int argc, const char *argv[])
{
func1();
return 0;
}
使用命令 gcc -c a.c编译得到a.o
得到的汇编文件如下:
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl %edi, -4(%rbp)
movq %rsi, -16(%rbp)
movl $0, %eax
call func1
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
b.cpp
void func1(void)
{}
得到的汇编文件如下:
.file "b.cpp"
.text
.globl _Z5func1v
.type _Z5func1v, @function
_Z5func1v:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
使用命令 g++ -c b.cpp编译得到b.o
使用命令gcc a.o b.o出现如下错误的提示
a.o: In function `main‘:
a.cpp:(.text+0x10): undefined reference to `func1‘
collect2: error: ld returned 1 exit status
修改b.cpp
extern "C" void func1(void)
{}
注:这里不能修改a.c,因为C语言中无法识别extern "C"
得到的汇编如下(g++ -S b.cpp):
.file "b.cpp"
.text
.globl func1
.type func1, @function
func1:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
这样在链接时就不会出错了。
标签:
原文地址:http://www.cnblogs.com/pengdonglin137/p/4846940.html