当前位置:   article > 正文

c++中extern “C“的作用及理解_extern c

extern c

1 意图

extern "C"是C++特有的指令(C无法使用该指令),目的在于支持C++与C混合编程。

2 作用

extern “C”的作用是告诉C++编译器用C规则编译指定的代码(除函数重载外,extern “C”不影响C++其他特性)。

3 原因

为什么要用C规则编译C++代码呢?

因为C和C++的编译规则不一样,主要区别体现在编译期间生成函数符号的规则不一致。

C++比C出道晚,但是增加了很多优秀的功能,函数重载就是其中之一。由于C++需要支持重载,单纯的函数名无法区分出具体的函数,所以在编译阶段就需要将形参列表作为附加项增加到函数符号中。如以下代码

  1. void Function(int a, int b)
  2. {
  3. printf("Hello!!! a = %d, b = %d\n", a, b);
  4. }

C和C++对应的的汇编码如下

  • C汇编结果
  1. ...
  2. Function:
  3. .LFB11:
  4. .cfi_startproc
  5. movl %esi, %edx
  6. xorl %eax, %eax
  7. movl %edi, %esi
  8. movl $.LC0, %edi
  9. jmp printf
  10. .cfi_endproc
  11. ...
  • C++汇编结果
  1. ...
  2. _Z8Functionii:
  3. .LFB12:
  4. .cfi_startproc
  5. movl %esi, %edx
  6. xorl %eax, %eax
  7. movl %edi, %esi
  8. movl $.LC0, %edi
  9. jmp printf
  10. .cfi_endproc
  11. ...

容易发现,两段代码的区别仅在于函数 Function(int a, int b) 编译后对应的符号不同

  • C:Function

  • C++_Z8Functionii

C++编出来的函数符号明显比C的多出了一些信息(如ii),这里多出来的后缀信息就是形参列表的参数类型信息。

好,C和C++编译规则对编译期间产生函数符号的影响我们知道了,但这又有什么用呢?

别急,很多人可能都遇到类似过这样的情况

  1. /* MyFunction.c */
  2. void Function(int a, int b)
  3. {
  4. printf("Hello!!! a = %d, b = %d\n", a, b);
  5. }
  6. /* main,cpp */
  7. extern void Function(int a, int b);
  8. int main()
  9. {
  10. Function(1, 2);
  11. }

C提供写了一个函数,用C++代码调用该函数,看起来没什么问题,但是编译的时候...

  1. /tmp/ccbkGl1J.o:在函数‘main’中:
  2. main.cpp:(.text.startup+0xf):对‘Function(int, int)’未定义的引用
  3. collect2: 错误:ld 返回 1

找不到对Function(int, int)的定义?怎么可能?

如果找到就玄幻了,大家注意观察,错误出在哪一步?对,编译阶段没报错,是链接的阶段报错了。我们来看看两个文件的汇编结果

  1. .file "MyFunction.c"
  2. .section .rodata.str1.1,"aMS",@progbits,1
  3. .LC0:
  4. .string "Hello!!! a = %d, b = %d\n"
  5. .text
  6. .p2align 4,,15
  7. .globl Function
  8. .type Function, @function
  9. Function:
  10. .LFB11:
  11. .cfi_startproc
  12. movl %esi, %edx
  13. xorl %eax, %eax
  14. movl %edi, %esi
  15. movl $.LC0, %edi
  16. jmp printf
  17. .cfi_endproc
  18. .LFE11:
  19. .size Function, .-Function
  20. .ident "GCC: (GNU) 6.4.1 20170727 (Red Hat 6.4.1-1)"
  21. .section .note.GNU-stack,"",@progbits
  1. .file "main.cpp"
  2. .section .text.startup,"ax",@progbits
  3. .p2align 4,,15
  4. .globl main
  5. .type main, @function
  6. main:
  7. .LFB0:
  8. .cfi_startproc
  9. subq $8, %rsp
  10. .cfi_def_cfa_offset 16
  11. movl $2, %esi
  12. movl $1, %edi
  13. call _Z8Functionii
  14. xorl %eax, %eax
  15. addq $8, %rsp
  16. .cfi_def_cfa_offset 8
  17. ret
  18. .cfi_endproc
  19. .LFE0:
  20. .size main, .-main
  21. .ident "GCC: (GNU) 6.4.1 20170727 (Red Hat 6.4.1-1)"
  22. .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++的其他特性),然后后面的事情就顺理成章了。

参考链接

extern C里面能有C++代码吗? - 知乎

Language linkage - cppreference.com

Standard C++

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/264447
推荐阅读
相关标签
  

闽ICP备14008679号