extern “C” 陷阱
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” 陷阱相关推荐
- typedef的四个用途和两大陷阱
typedef的四个用途和两个陷阱 --------------------------------- 用途一: 定义一种类型的别名,而不只是简单的宏替换.可以用作同时声明指针型的多个对象.比如: c ...
- C陷阱与缺陷学习笔记
导读 程序是由符号(token)序列所组成的,将程序分解成符号的过程,成为"词法分析". 符号构成更大的单元--语句和声明,语法细节最终决定了语义. 词法陷阱 符号(token)指 ...
- typedef 的四个用途和两大陷阱
>>>>>用途一: 定义一种类型的别名,而不只是简单的宏替换.可以用作同时声明指针型的多个对象.比如: char* pa, pb; // 这多数不符合我们的意图,它只声明 ...
- typedef的四个用途和两个陷阱
typedef的四个用途和两个陷阱 --------------------------------- 用途一: 定义一种类型的别名,而不只是简单的宏替换.可以用作同时声明指针型的多个对象.比如: c ...
- typedef四用途与两陷阱
typedef用来声明一个别名,typedef后面的语法,是一个声明.本来笔者以为这里不会产生什么误解的,但结果却出乎意料,产生误解的人不在少数.罪魁祸首又是那些害人的教材.在这些教材中介绍typed ...
- 阅读《C陷阱与缺陷》的知识增量
看完<C陷阱与缺陷>,忍不住要重新翻一下,记录一下与自己的惯性思维不符合的地方.记录的是知识的增量,是这几天的流量,而不是存量. 这本书是在ASCI C/C89订制之前写的,有些地方有疏漏 ...
- 深入理解C语言系列之C语言语法陷阱(考题常设置的陷阱点、必须避免的错误和缺陷类型)
1.赋值与等于 =:赋值运算,a=3;表示的是将3赋值给a变量. ==:比较运算,a==3;表示判断a是否等于3,若等于则返回1,否则返回0. 2.按位与.逻辑与 &&:逻辑与,是一种 ...
- C陷阱与缺陷阅读笔记(上)
词法陷阱 1.贪心法 C编译器对C语言符号的识别,基于每一个符号应该包含尽可能多的字符原则. 如果输入流截止至某个字符之前都已经分解成为一个个符号,那么下一个符号将包括从该字符之后可能组成一个符号的最 ...
- 揭秘 typedef四用途与两陷阱
原文出处:http://niehan.blog.techweb.com.cn/archives/325.html typedef用来声明一个别名,typedef后面的语法,是一个声明.本来笔者以为这里 ...
最新文章
- atom创建html文件夹,如何在Atom文本编辑器中按文件类型设置默认语法?
- Python3.6字符串新特性
- python中int对象不可调用_'int'对象在python中不可调用
- 5G加速向纵深发展 中国电信联合产业链开展“5G创新终端商用合作行动”
- JavaSE-22 反射
- 如何编写一个高效的Testbench?
- 0基础学嵌入式:嵌入式linux视频教程免费分享!
- select获取下拉框的值 下拉框默认选中
- HHL论文及代码理解(Generalizing A Person Retrieval Model Hetero- and Homogeneously ECCV 2018)...
- 我创建了一个苹果园小区群和河北老乡群
- ORACLE解决表空间不释放空间
- mtk平台gsensor,msensor方向确定方法
- 读Zepto源码之Ajax模块 1
- CSS3做齿轮旋转的动画
- sarscape5.6.2 结果在arcgis中制图(2可以在envi里调好色带导入arcgis)
- 顶点片元Shader(Unity)
- mysql subpartitions_mysql分区报错:Too many partitions (including subpartitions) 处理
- SSH配置公钥后仍需要输入密码问题解析
- ASP.NET MVC5 + EF6 通过model层创建controller时需要重新生成解决方案。
- Python中的三维坐标空间