赞
踩
extern "C"是C++特有的指令(C无法使用该指令),目的在于支持C++与C混合编程。
extern “C”的作用是告诉C++编译器用C规则编译指定的代码(除函数重载外,extern “C”不影响C++其他特性)。
为什么要用C规则编译C++代码呢?
因为C和C++的编译规则不一样,主要区别体现在编译期间生成函数符号的规则不一致。
C++比C出道晚,但是增加了很多优秀的功能,函数重载就是其中之一。由于C++需要支持重载,单纯的函数名无法区分出具体的函数,所以在编译阶段就需要将形参列表作为附加项增加到函数符号中。如以下代码
- void Function(int a, int b)
- {
- printf("Hello!!! a = %d, b = %d\n", a, b);
- }
C和C++对应的的汇编码如下
- ...
- Function:
- .LFB11:
- .cfi_startproc
- movl %esi, %edx
- xorl %eax, %eax
- movl %edi, %esi
- movl $.LC0, %edi
- jmp printf
- .cfi_endproc
- ...
- ...
- _Z8Functionii:
- .LFB12:
- .cfi_startproc
- movl %esi, %edx
- xorl %eax, %eax
- movl %edi, %esi
- movl $.LC0, %edi
- jmp printf
- .cfi_endproc
- ...
容易发现,两段代码的区别仅在于函数 Function(int a, int b) 编译后对应的符号不同
C:Function
C++:_Z8Functionii
C++编出来的函数符号明显比C的多出了一些信息(如ii),这里多出来的后缀信息就是形参列表的参数类型信息。
好,C和C++编译规则对编译期间产生函数符号的影响我们知道了,但这又有什么用呢?
别急,很多人可能都遇到类似过这样的情况
- /* MyFunction.c */
- void Function(int a, int b)
- {
- printf("Hello!!! a = %d, b = %d\n", a, b);
- }
-
-
- /* main,cpp */
- extern void Function(int a, int b);
-
- int main()
- {
- Function(1, 2);
- }
C提供写了一个函数,用C++代码调用该函数,看起来没什么问题,但是编译的时候...
- /tmp/ccbkGl1J.o:在函数‘main’中:
- main.cpp:(.text.startup+0xf):对‘Function(int, int)’未定义的引用
- collect2: 错误:ld 返回 1
找不到对Function(int, int)的定义?怎么可能?
如果找到就玄幻了,大家注意观察,错误出在哪一步?对,编译阶段没报错,是链接的阶段报错了。我们来看看两个文件的汇编结果
- .file "MyFunction.c"
- .section .rodata.str1.1,"aMS",@progbits,1
- .LC0:
- .string "Hello!!! a = %d, b = %d\n"
- .text
- .p2align 4,,15
- .globl Function
- .type Function, @function
- Function:
- .LFB11:
- .cfi_startproc
- movl %esi, %edx
- xorl %eax, %eax
- movl %edi, %esi
- movl $.LC0, %edi
- jmp printf
- .cfi_endproc
- .LFE11:
- .size Function, .-Function
- .ident "GCC: (GNU) 6.4.1 20170727 (Red Hat 6.4.1-1)"
- .section .note.GNU-stack,"",@progbits
- .file "main.cpp"
- .section .text.startup,"ax",@progbits
- .p2align 4,,15
- .globl main
- .type main, @function
- main:
- .LFB0:
- .cfi_startproc
- subq $8, %rsp
- .cfi_def_cfa_offset 16
- movl $2, %esi
- movl $1, %edi
- call _Z8Functionii
- xorl %eax, %eax
- addq $8, %rsp
- .cfi_def_cfa_offset 8
- ret
- .cfi_endproc
- .LFE0:
- .size main, .-main
- .ident "GCC: (GNU) 6.4.1 20170727 (Red Hat 6.4.1-1)"
- .section .note.GNU-stack,"",@progbits
可以看到,MyFunction.s(源文件为.c文件)中定义的是Function,而main.s(源文件为.cpp文件)中调用的是_Z8Functionii,函数名不一样,所以连接的时候找不到函数实现。到这里我们知道C和C++编译期间后得到的函数符号不同,所以C++代码和C代码不能互相调用。
要想实现C、C++混合编程该怎么办呢?让编译后的函数符号一致;
怎么一致呢?用extern "C"!
所以,extern “C”的作用就是告诉C++编译器,将指定的函数用C规则编译(注意,除了函数重载外,extern “C”不影响C++的其他特性),然后后面的事情就顺理成章了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。