【C++】extern "C"详解

饭宝  金牌会员 | 2022-11-14 16:34:47 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 995|帖子 995|积分 2985

先说结论 :  extern "C"只影响到链接期的name mangling
什么是name mangling?
    请看 :  C++函数重载的实现机制之name mangling - 知乎 (zhihu.com)
举个例子 :
  1. // external.h
  2. #ifdef __cplusplus
  3. extern "C" {
  4. #endif
  5. void external();
  6. #ifdef __cplusplus
  7. }
  8. #endif
复制代码
  1. // external.cc
  2. #include "external.h"
  3. template <typename T> // 这明显是C++特性, gcc是无法编译的
  4. void external()
  5. {
  6.     T a;
  7. }
复制代码
  1. // main.c
  2. #include "external.h"
  3. int main()
  4. {
  5.     external();
  6. }
复制代码
在这里 : main函数里面调用了c++函数external(), 如果这个函数没被 extern "C"包裹, 会出现"undefined reference to"的错误.
这是因为g++、clang++都优先判断后缀名 ( 除非自己改option ), 就会对external.cc文件进行C++方式编译 : 
  由于c++重载机制的存在, 编译器只能在你命名之后 再悄悄重新给函数做个标记, 这个标记名也是有规则的, 比如g++, [ _Z + 函数名长度 + v / i ...标记符 ] .
  external()函数被compiler赋予一个"符号", 如果是gcc, 这个符号就是external;
                       如果是g++, 这个符号是 _Z8externalv 或者_Z8externali;
                            而clang++更夸张, 变成了"?external@@YAHXZ"或者"?external@@YAHH@Z"这种怪物.
然后把obj文件中定义和引用的global variable和function存到一张"符号表"中方便链接器的工作.
------------------------------------------------------------------------------------------------------------------
             名字             |               类型                |          是否可被外部引用            |             区域
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      _Z8externalv     |           定义, 引用            |                       可                       |           代码段
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      _Z8externali      |           定义, 引用            |                       可                       |           代码段
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    main            |               定义                 |                                                  |

-------------------------------------------------------------------------------------------------------------------
  链接器说"我开始找了 ! ", 然后给main函数找external(), 发现没有c版本的, 只有c++版本的呀, 它干不了了, "undefined reference to external".
  如果你把声明extern "C",  链接器才能找到c版本的external(), 加上依赖库/模块 全打包起来. 还是拿gnu来说吧, c程序会打包libgcc.a静态库,c++程序则会打包很多libstdc++.a的东西和一些各式各样的依赖, 这也是一般c++程序大小都要pure c大的原因, 在嵌入式平台这种差距尤为明显.
  人家卡马乔也有话说的 : " 我找的是什么表啊, 你这个表什么都有 我都能找到为什么不能链接? "
  c文件和c++文件直接链接在一起, 链接器应该用libgcc这个链子还是libstdc++呢?它没法去判断啊,只能你骗他一下这是c文件, 用libgcc去链.
 
所以, 你extern "C"包裹函数的声明, 并不会改变函数体内语句的实际编译方式, 因为它的定义仍在.cc文件里, g++仍会优先将它以c++的方式编译. 但是函数名的确是以c的方式编去了.
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

饭宝

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表