关于“#ifdef __cplusplus”
CC++语言在编译的时候为了解决函数的多态问题,会将函数名和参数联合起来生成一个中间的函数名称,而C语言则不会,因此会造成链接时找不到对应函数的情况,此时C函数就需要用extern “C”进行链接指定,这告诉编译器,请保持我的名称,不要给我生成用于链接的中间函数名。
时常在cpp的代码之中看到这样的代码:
#ifdef __cplusplus extern "C" { #endif //一段代码 #ifdef __cplusplus } #endif
这样的代码到底是什么意思呢?首先,__cplusplus是cpp中的自定义宏,那么定义了这个宏的话表示这是一段cpp的代码,也就是说,上面的代码的含义是:如果这是一段cpp的代码,那么加入extern "C"{和}处理其中的代码。
要明白为何使用extern "C",还得从cpp中对函数的重载处理开始说起。在c++中,为了支持重载机制,在编译生成的汇编码中,要对函数的名字进行一些处理,加入比如函数的返回类型等等.而在C中,只是简单的函数名字而已,不会加入其他的信息.也就是说:C++和C对产生的函数名字的处理是不一样的.
比如下面的一段简单的函数,我们看看加入和不加入extern "C"产生的汇编代码都有哪些变化:
int f(void) { ; }
在加入extern "C"的时候产生的汇编代码是:
.file "test.cxx" .text .align .globl _f .def _f; .scl 2; .type 32; .endef _f: pushl %ebp movl %esp, %ebp movl $, %eax popl %ebp ret
但是不加入了extern "C"之后
.file "test.cxx" .text .align .globl __Z1fv .def __Z1fv; .scl 2; .type 32; .endef __Z1fv: pushl %ebp movl %esp, %ebp movl $, %eax popl %ebp ret
两段汇编代码同样都是使用gcc -S命令产生的,所有的地方都是一样的,唯独是产生的函数名,一个是_f,一个是__Z1fv。
明白了加入与不加入extern "C"之后对函数名称产生的影响,我们继续我们的讨论:为什么需要使用extern "C"呢?C++之父在设计C++之时,考虑到当时已经存在了大量的C代码,为了支持原来的C代码和已经写好C库,需要在C++中尽可能的支持C,而extern "C"就是其中的一个策略。
试想这样的情况:一个库文件已经用C写好了而且运行得很良好,这个时候我们需要使用这个库文件,但是我们需要使用C++来写这个新的代码。如果这个代码使用的是C++的方式链接这个C库文件的话,那么就会出现链接错误.我们来看一段代码:首先,我们使用C的处理方式来写一个函数,也就是说假设这个函数当时是用C写成的:
//f1.c
extern "C"
{
void f1()
{
return;
}
}
编译命令是:gcc -c f1.c -o f1.o 产生了一个叫f1.o的库文件。再写一段代码调用这个f1函数:
// test.cxx
//这个extern表示f1函数在别的地方定义,这样可以通过
//编译,但是链接的时候还是需要
//链接上原来的库文件.
extern void f1();
int main()
{
f1();
return 0;
}
通过gcc -c test.cxx -o test.o 产生一个叫test.o的文件。然后,我们使用gcc test.o f1.o来链接两个文件,可是出错了,错误的提示是:
test.o(.text + 0x1f):test.cxx: undefine reference to 'f1()'
也就是说,在编译test.cxx的时候编译器是使用C++的方式来处理f1()函数的,但是实际上链接的库文件却是用C的方式来处理函数的,所以就会出现链接过不去的错误:因为链接器找不到函数。
因此,为了在C++代码中调用用C写成的库文件,就需要用extern "C"来告诉编译器:这是一个用C写成的库文件,请用C的方式来链接它们。
比如,现在我们有了一个C库文件,它的头文件是f.h,产生的lib文件是f.lib,那么我们如果要在C++中使用这个库文件,我们需要这样写:
extern "C"
{
#include "f.h"
}
回到上面的问题,如果要改正链接错误,我们需要这样子改写test.cxx:
extern "C"
{
extern void f1();
}
int main()
{
f1();
return 0;
}
重新编译并且链接就可以过去了.
总结
C和C++对函数的处理方式是不同的.extern "C"是使C++能够调用C写作的库文件的一个手段,如果要对编译器提示使用C的方式来处理函数的话,那么就要使用extern "C"来说明。
关于“#ifdef __cplusplus”的更多相关文章
- #ifdef __cplusplus extern "C" { #endif
1.在好多程序中我们会遇到下面代码段 #ifdef __cplusplus extern "C" { #endif //c语法代码段 #ifdef __ ...
- #ifdef __cplusplus extern "C"
#ifdef __cplusplus extern "C" { #endif //一段代码 #ifdef __cplusplus } #endif首先,__cplusplus是cp ...
- #ifdef __cplusplus
转自:http://www.2cto.com/kf/201302/191822.html #ifdef __cplusplus,一般用于将C++代码以标准C形式输出(即以C的形式被调用),这是因为C+ ...
- 【转】#ifdef __cplusplus深度剖析
原文:http://bbs.ednchina.com/BLOG_ARTICLE_251752.HTM 时常在cpp的代码之中看到这样的代码: #ifdef __cplusplus extern ...
- c++ 学习笔记 c++ 引用C库注意点:#ifdef __cplusplus 倒底是什么意思?
时常在cpp的代码之中看到这样的代码: #ifdef __cplusplus extern "C" { #endif //一段代码 #ifdef __cplusplus } #en ...
- 几乎每个文件里面都有 #ifdef __cplusplus extern "C" { #endif 可我没找到程序里那个地方定义了__cplusplus 啊?这又是怎么回事呢?
我们的C语言有个进化版,叫C++,这个想必楼主知道,Keil MDK是支持C++编程的,也就是说,你可以用C语言或者C++写你的程序,都可以. 但是,有一个问题,就是头文件的问题,C语言写的头文件C+ ...
- #ifdef __cplusplus extern c #endif 的作用
#ifdef __cplusplus // C++编译环境中才会定义__cplusplus (plus就是"+"的意思) extern "C" { // 告诉编 ...
- “#ifdef __cplusplus extern "C" { #endif”的定义
平时我们在linux c平台开发的时候,引用了一些Cpp或者C的代码库,发现一些头文件有如下代码条件编译. #ifdef __cplusplus extern "C" { #end ...
- #ifdef __cplusplus extern "C" {代码} 倒底是什么意思?
时常在cpp的代码之中看到这样的代码: #ifdef __cplusplus extern "C" { #endif //一段代码 #ifdef __cplusplus } # ...
随机推荐
- 27 Remove Element
Given an array and a value, remove all instances of that value in place and return the new length. T ...
- C期未考试参考答案
输入10个数,要求编写一个排序函数,能够实现按绝对值从大到小排序.在主函数中输入10个数.输出排序后的10个数 #include<stdio.h>#include<math.h> ...
- JS基础如何理解对象
这几天跟几个同事聊天发现他们对javascript什么时候该用new都不是很了解. 1.javascript的function什么时候该new什么时候不该new?我觉得主要的问题还是集中在javasc ...
- redhat系列yum本地源配置
1.挂载光盘,本示例挂载在/mnt下. 2.清除系统带的.repo文件,rm -f /etc/yum.repos.d/* 3.编辑自己的repo文件,内容如下: [local_server] (库 ...
- undo_retention:确定最优的撤销保留时间
使用下面的公式来计算undo_retention参数的值: undo_retention=undo size/(db_block_size * undo_block_per_sec) 可以通过提交下面 ...
- RedHat6.5网卡问题总结
问题描述:准备用RedHat6.5安装Oracle 12c RAC,系统环境准备好后发现,新版本的RedHat网卡配置跟以前不大一样,总结问题与解决方法如下: 1.找不到eth0文件 在使用RedHa ...
- Emacs配置erlang开发环境(.emacs 文件)
以前都是用sublime写erlang代码,好处不多说,主要是觉得一点不好用,不能实现函数跳转,及其不方便,尤其是代码一多,头疼.后来折腾过IntelliJ,下了个收费$0.00的版本,风格还是挺稀饭 ...
- 京东区块排版负margin用法
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- javascript第十一课,string对象
length: //字符串长度,索引从0开始 var str='说东方闪电方式的'; alert(str.length); charAt(index); var n='阿斯顿发生打算'; n.cha ...
- 郁闷的C小加(一)(后缀表达式)
郁闷的C小加(一) 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 我们熟悉的表达式如a+b.a+b*(c+d)等都属于中缀表达式.中缀表达式就是(对于双目运算符来说 ...