extern “C” 陷阱

extern “C”通常使用在C++中,由于C++支持函数重载,命名空间等技术,故C++编译器在编译C++代码时会对函数进行签名,也就是说编译后的函数名将发生变化。例如我们有如下的代码:

test.cpp

int fun(int a)

{

///nothing.

}

在Ubuntu下用g++编译这个cpp文件获取它的目标文件test.o,命令:gcc -c test.cpp我们可以用GNU binutils工具readelf来查看test.o中的符号信息,命令:readelf -s test.o

输出如下:

可以看到所有的符号中并没有出现fun,这是因为g++对函数进行了签名,唯一和fun相似的符号就是_Z3funi,那么这个符号是否就是test.cpp中的fun函数呢?我们可以用c++filt(用来查看符号的未被签名前的原型)来进行验证:c++filt _Z3funi

可以看到在test.o中的符号_Z3funi对应的就是test.cpp中的fun函数。如果我们要阻止c++编译器这种签名机制,extern “C”就派上了用场。我们在fun前添加extern “C”。

extern “C” int fun(int a)

{

///nothing.

}

重新编译我们再查看test.o中的符号表:

可以看到加上extern “C” 函数fun就没有被签名。

在日常开发中extern “C” 使用在C++调用C编写的动态库的接口时显示声明C++中的接口不被签名,从而能正常调用C编写的动态库。下面看一个例子:

print.c:

#include <stdio.h>

void print(int a, int b)

{

printf(“sum = %d\n”, a+b);

}

使用命令:gcc -shared -fPIC -o LibPrint.so print.c 来编译生成动态库LibPrint.so。

程序主模块:

main.cpp:

extern “C” void print(int a); ///这里只有一个int参数

int main()

{

print(1);

return 0;

}

使用命令:g++ -o main main.cpp ./LibPrint.so 来编译生成可执行程序main

可以看到编译通过了,没有报任何错误。大家可能会疑惑在动态库中的函数原型为void print(int,int),但在main.cpp中函数原型为void print(int),应该要报找不到符号。程序之所以能编译通过是因为编译器在进行连接时发现print是一个外部符号(为使用了extern “C”声明,main.o模块中函数print并没有被签名),便在动态库LibPrint.so中寻找,而LibPrint中定义了该符号,故能编译通过。

最可怕的是产生的可执行程序能够运行且不会core出,因为LibPrint.so中的print函数只是跨越了自己参数栈多取了参数栈后面的一个数据(int b),而这是合法的(访问的数据还未越界,还在程序栈内)。

综上所述当我们在使用外部用C开发的第三方库需要使用extern “C”时,尤其是在第三方库更新时要确认第三方库的接口是否改变,自己程序中接口声明是否和库中一致。

extern “C” 陷阱相关推荐

  1. typedef的四个用途和两大陷阱

    typedef的四个用途和两个陷阱 --------------------------------- 用途一: 定义一种类型的别名,而不只是简单的宏替换.可以用作同时声明指针型的多个对象.比如: c ...

  2. C陷阱与缺陷学习笔记

    导读 程序是由符号(token)序列所组成的,将程序分解成符号的过程,成为"词法分析". 符号构成更大的单元--语句和声明,语法细节最终决定了语义. 词法陷阱 符号(token)指 ...

  3. typedef 的四个用途和两大陷阱

    >>>>>用途一: 定义一种类型的别名,而不只是简单的宏替换.可以用作同时声明指针型的多个对象.比如: char* pa, pb; // 这多数不符合我们的意图,它只声明 ...

  4. typedef的四个用途和两个陷阱

    typedef的四个用途和两个陷阱 --------------------------------- 用途一: 定义一种类型的别名,而不只是简单的宏替换.可以用作同时声明指针型的多个对象.比如: c ...

  5. typedef四用途与两陷阱

    typedef用来声明一个别名,typedef后面的语法,是一个声明.本来笔者以为这里不会产生什么误解的,但结果却出乎意料,产生误解的人不在少数.罪魁祸首又是那些害人的教材.在这些教材中介绍typed ...

  6. 阅读《C陷阱与缺陷》的知识增量

    看完<C陷阱与缺陷>,忍不住要重新翻一下,记录一下与自己的惯性思维不符合的地方.记录的是知识的增量,是这几天的流量,而不是存量. 这本书是在ASCI C/C89订制之前写的,有些地方有疏漏 ...

  7. 深入理解C语言系列之C语言语法陷阱(考题常设置的陷阱点、必须避免的错误和缺陷类型)

    1.赋值与等于 =:赋值运算,a=3;表示的是将3赋值给a变量. ==:比较运算,a==3;表示判断a是否等于3,若等于则返回1,否则返回0. 2.按位与.逻辑与 &&:逻辑与,是一种 ...

  8. C陷阱与缺陷阅读笔记(上)

    词法陷阱 1.贪心法 C编译器对C语言符号的识别,基于每一个符号应该包含尽可能多的字符原则. 如果输入流截止至某个字符之前都已经分解成为一个个符号,那么下一个符号将包括从该字符之后可能组成一个符号的最 ...

  9. 揭秘 typedef四用途与两陷阱

    原文出处:http://niehan.blog.techweb.com.cn/archives/325.html typedef用来声明一个别名,typedef后面的语法,是一个声明.本来笔者以为这里 ...

最新文章

  1. atom创建html文件夹,如何在Atom文本编辑器中按文件类型设置默认语法?
  2. Python3.6字符串新特性
  3. python中int对象不可调用_'int'对象在python中不可调用
  4. 5G加速向纵深发展 中国电信联合产业链开展“5G创新终端商用合作行动”
  5. JavaSE-22 反射
  6. 如何编写一个高效的Testbench?
  7. 0基础学嵌入式:嵌入式linux视频教程免费分享!
  8. select获取下拉框的值 下拉框默认选中
  9. HHL论文及代码理解(Generalizing A Person Retrieval Model Hetero- and Homogeneously ECCV 2018)...
  10. 我创建了一个苹果园小区群和河北老乡群
  11. ORACLE解决表空间不释放空间
  12. mtk平台gsensor,msensor方向确定方法
  13. 读Zepto源码之Ajax模块 1
  14. CSS3做齿轮旋转的动画
  15. sarscape5.6.2 结果在arcgis中制图(2可以在envi里调好色带导入arcgis)
  16. 顶点片元Shader(Unity)
  17. mysql subpartitions_mysql分区报错:Too many partitions (including subpartitions) 处理
  18. SSH配置公钥后仍需要输入密码问题解析
  19. ASP.NET MVC5 + EF6 通过model层创建controller时需要重新生成解决方案。
  20. Python中的三维坐标空间

热门文章

  1. 成长不可或缺的財富——肥皂剧和八卦节目带给我的成长
  2. IOT平台架构设计思路
  3. office2013视频教程免费观看
  4. ui设计师css和html,27个HTML5和CSS3的网站设计欣赏
  5. Android setTag 使用
  6. CF 29A Spit Problem
  7. 听相声有感(三)——拼积累
  8. Android 4.1 (Jelly Bean) 源码编译过程总结
  9. android LeanCloud SDK部署
  10. “五胡乱华”是两汉和曹魏埋下的隐患,为何后世只骂司马家?