时常在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) 

return 1; 
}
  在加入extern "C"的时候产生的汇编代码是:

.file "test.cxx" 
.text 
.align 2 
.globl _f 
.def _f; .scl 2; .type 32; .endef 
_f: 
pushl %ebp 
movl %esp, %ebp 
movl $1, %eax 
popl %ebp 
ret
  但是不加入了extern "C"之后

.file "test.cxx" 
.text 
.align 2 
.globl __Z1fv 
.def __Z1fv; .scl 2; .type 32; .endef 
__Z1fv: 
pushl %ebp 
movl %esp, %ebp 
movl $1, %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"来说明。

探索C++的秘密之详解extern C相关推荐

  1. 7-33 地下迷宫探索 (30 分)(思路加详解)

    一:题目 7-33 地下迷宫探索 (30 分) 地道战是在抗日战争时期,在华北平原上抗日军民利用地道打击日本侵略者的作战方式.地道网是房连房.街连街.村连村的地下工事,如下图所示. 我们在回顾前辈们艰 ...

  2. 华硕h81m一k跳线图_主板跳线接法的所有秘密图文详解(适合新手)

    作为一名新手,要真正从头组装好自己的电脑并不容易,也许你知道CPU应该插哪儿,内存应该插哪儿,但遇到一排排复杂跳线的时候,很多新手都不知道如何下手.钥匙开机其实并不神秘 还记不记得你第一次见到装电脑的 ...

  3. 《C语言杂记》详解extern “C“

    在嵌入式开发过程中,你是否经常看到类似下面的代码. #ifdef __cplusplusextern "C" {#endif -- #ifdef __cplusplus } #en ...

  4. 探索JAVA并发 - 线程池详解

    作者:acupt,80后资深Java工程师一枚!架构师社区合伙人! 线程池是并发编程中必不可少的一种工具,也是面试高频话题. 线程池,即管理着若干线程的资源池(字面意思).相比于为每个任务分配一个线程 ...

  5. 深度详解 Android 之 Context

    文章目录 一. 简介 1.1 Context 概述 1.2 Context 体系结构 1.3 Context 作用域 1.4 总结 二. Context 详解 2.1 Application Cont ...

  6. extern用法详解(转)

    extern用法详解(转)       1 基本解释 extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义. 另外,extern ...

  7. extern用法详解

    [转]extern用法详解 Posted on 2011-08-16 11:15 单鱼游弋 阅读(98) 评论(0)编辑收藏 1 基本解释 extern可以置于变量或者函数前,以标示变量或者函数的定义 ...

  8. 通过 JFR 与日志深入探索 JVM - TLAB 原理详解

    全系列目录:通过 JFR 与日志深入探索 JVM - 总览篇 什么是 TLAB? TLAB(Thread Local Allocation Buffer)线程本地分配缓存区,这是一个线程专用的内存分配 ...

  9. K8S探索之Service+Flannel本机及跨主机网络访问原理详解

    简介 在上篇中,我们部署了我们的应用,但我们访问是直接在应用所在的容器,使用IP+Port的方式直接访问的,style不够k8s,本篇文章我们将使用service和跨主机访问 内容概览 目前我们的应用 ...

最新文章

  1. beanstalkd消息队列在生产环境的应用
  2. 剑指Offer(Java实现)把二叉树打印成多行
  3. 材料成型计算机模拟第三版,材料成型计算机模拟实验报告模板学习.doc
  4. CSS的clear去除清除浮动元素
  5. 15.10.4 捕获异常
  6. Linux文件权限查看及修改命令chmod,chown
  7. 无法打开“XXXX”,因为Apple无法检查其是否包含恶意软件。怎么解决?
  8. 豆瓣评分9.4分!这部大片你不应该错过,每一秒都是不敢看的残忍!
  9. Everyday is an Opportunity
  10. numpy 中shape的用法
  11. .Net消息队列学习(一)
  12. php 新浪微博登陆,PHP使用新浪微博登入第三方网站实例代码
  13. 计算机组成原理--填空,简答,判断,计算大题
  14. ThreadPoolExecutor中的submit()方法详细讲解
  15. USB中的端点详细了解
  16. AARRR模型 | 用户留存套路与习惯养成
  17. 悟空CRM(基于jfinal+vue+ElementUI的前后端分离的开源CRM系统)
  18. 使用elasticSearch搭建本地以图搜图服务
  19. php人事考勤系统,基于PHPMySQL的考勤系统
  20. [Android Pro] Android TypedValue.applyDimension()的用法

热门文章

  1. vue.js分页组件(新手学习记录)
  2. 2018届应届生android面试总结
  3. 面向对象(继承,多态)
  4. hive_0.11中文用户手册
  5. 24. [Ext JS 4] 实战之Load Mask(加载遮罩)的显示与隐藏
  6. Oracle:集群因子
  7. Nagios监控系统详解
  8. web.xml配置(转)
  9. Android语音录入与邮件发送
  10. 域内操作主机角色一向让很多人很头痛,我归纳总结一下,希望对大家有帮助...