extern "C" 学习笔记
来源:互联网 发布:js indexof 判断 编辑:程序博客网 时间:2024/06/05 10:11
1.引言
有一道经典的程序员面试题,如下:
//为什么标准头文件都有和以下 相似的结构?
#ifndef DuNiangHeadFile#define DuNiangHeadFile #ifdef __cplusplusextern "C" {#endif /*bla bla bla*/ #ifdef __cplusplus}#endif #endif /* DuNiangHeadFile */
对于头文件中的编译宏的作用,显然是为了防止该头文件被重复引用。
#ifndef DuNiangHeadFile#define DuNiangHeadFile #endif /* DuNiangHeadFile */
那么剩下代码的作用又是什么呢?
#ifdef __cplusplusextern "C" {#endif /*bla bla bla*/ #ifdef __cplusplus}#endif
这正是本篇博文所要阐述的内容。下面我们进入正题。
2.揭密extern "C"
从直观上来讲,extern "C" 显然有两层含义。其一,是 被它修饰的目标是“extern”,即该目标具有外部链接性,可以在其他编译单元(文件)中被引用。其二,被它修饰的目标是“C”类型的,即编译器或链接器要按照C的编译规则来对其进行编译或链接。
之所以采用这种方式,是因为C和C++这两种语言之间的一些差异导致的。
作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为:
int myFunc(int a, int b);
经过C++编译器编译之后 ,在其目标文件.o 文件中,有一个_Z10myFuncii 符号,这个符号就代表了源文件中的int myFunc(int a, int b)函数了。不同的编译器可能生成不同的名字,但是都采用了相同的机制,即C++ Primer中所说的“名字粉碎”(name mangling)或“名字修饰”(name decoration)。
_Z10myFuncii 这样的名字包含了函数名、函数参数数量及类型信息,其最后的两个字符i 就表示第一参数和第二参数都是整型。C++就是靠这种机制来实现函数重载的。在链接阶段,链接器就会从生成的 .o目标文件中寻找_Z10myFuncii 这样的符号,从而生成可执行文件。
而对于加extern "C"声明后,即假设某个函数的原型为:
#ifdef __cplusplusextern "C" {#endif int myFunc(int a, int b);#ifdef __cplusplus}#endif
编译生成myFunc函数的目标代码时,没有对其名字进行特殊处理,采用了C语言的方式;链接器在为其他的目标代码寻找myFunc函数调用时,寻找的是未经修改的符号名_myFunc。正是因为如此,才实现了C++与C及其它语言的混合编程。
3.extern "C"的惯用法
明白了C++中extern "C"的基本原理,下面我们来具体分析一下extern "C"的常用技巧。
(1)在C++中引用C语言中的函数和变量,在包含C语言头文件(假设为cExample.h)时,需进行下列处理:
extern "C"{ #include "cExample.h"}
而在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern "C"声明,在C文件的头文件中直接extern "C"时会出现编译语法错误。但是,说的是直接使用会出错。如果略施小计,C语言头文件中也是可以使用extern "C"的。
用g++编译cpp程序时,编译器会定义宏 __cplusplus ,可根据__cplusplus是否已经定义,来决定是否需要extern "C"。
#ifdef __cpluscplus extern "C" { #endif //正常C语言头文件 #ifdef __cplusplus } #endif
这是你可以修改C语言.h文件的情况。
(2)当你不能修改C语言.h文件,比如这个头文件是公司里的前辈写的,或者,公司规定禁止修改没有BUG的历史遗留代码,以防引入不必要的新Bug。
同时,.h文件中没有extern "C"关键字,而你的C++程序又要链接使用由C编译好的.o目标文件。这时该怎么办呢?
可以这样,在你的c++文件中,包含该模块的头文件时加上extern "C", 如下:
extern "C" { #include "old_C_HeadFile.h" }
如果仅仅使用其中的一个函数,而不需要include整个头文件时,也可以单独声明该函数,如下:
extern "C" { int myFunc(int , int);}
这样,C++编译器在编译,或链接器在链接的时候,就会以C风格在目标文件中生成或寻找目标符号了。
同理,如果C++调用一个C语言编写的.DLL时,当包括.DLL的头文件或声明接口函数时,应加extern "C" { }。这突然让我想到了com组件技术。
- extern "C" 学习笔记
- C++学习笔记 extern C
- extern "C" 阅读笔记
- extern “C” 阅读笔记
- extern C学习
- C/C++学习笔记(十二)extern的详解
- C语言学习笔记之static和extern(十六)
- C程序设计语言(K&R)学习笔记--5.extern小结
- 【C语言学习笔记】关键字:typedef、static和extern
- c语言学习笔记之static和extern关键字
- c语言学习笔记---存储类型auo,register,extern,static
- C语言文件操作包括static,extern的学习笔记
- extern "C" 阅读笔记 zz
- #ifdef __cplusplus extern "C" 笔记
- C++学习之extern "C"
- extern ''C'' 的 学习浅谈
- 学习笔记—extern关键字
- C语言学习之extern "C"
- ExtJS 4.*基础概念总结(基于Ext4.2.1)
- 第一天
- ubuntu下git的安装及使用
- 16进制转RGB (PHP代码函数)
- There is no Action mapped for namespace [/] and action name
- extern "C" 学习笔记
- CentOS下ssh登录限制ip的方法
- spring 定时器配置
- Android混淆打包
- 随机数组遍历
- iOS制作Framework相关
- [LeetCode] Search for a Range (sorted integers array,find start & end position of a target number)
- iOS “自定义返回按钮”与“系统侧滑”的组合使用
- Tomcat 和 Jetty 下 JNDI 配置 DBCP 连接池