探索C++的秘密之详解extern
时常在cpp的代码之中看到这样的代码:
|
#ifdef __cplusplus |
这样的代码到底是什么意思呢?首先,__cplusplus是cpp中的自定义宏,那么定义了这个宏的话表示这是一段cpp的代码,也就是说,上面的代码的含义是:如果这是一段cpp的代码,那么加入extern "C"{和}处理其中的代码。
要明白为何使用extern "C",还得从cpp中对函数的重载处理开始说起。在c++中,为了支持重载机制,在编译生成的汇编码中,要对函数的名字进行一些处理,加入比如函数的返回类型等等。而在C中,只是简单的函数名字而已,不会加入其他的信息.也就是说:C++和C对产生的函数名字的处理是不一样的。
比如下面的一段简单的函数,我们看看加入和不加入extern "C"产生的汇编代码都有哪些变化:
|
int f(void) } |
在加入extern "C"的时候产生的汇编代码是:
|
.file "test.cxx" |
但是不加入了extern "C"之后:
|
.file "test.cxx" |
两段汇编代码同样都是使用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 |
编译命令是:gcc -c f1.c -o f1.o 产生了一个叫f1.o的库文件。再写一段代码调用这个f1函数:
|
// test.cxx |
通过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" |
回到上面的问题,如果要改正链接错误,我们需要这样子改写test.cxx:
|
extern "C" |
重新编译并且链接就可以过去了。
总结
C和C++对函数的处理方式是不同的.extern "C"是使C++能够调用C写作的库文件的一个手段,如果要对编译器提示使用C的方式来处理函数的话,那么就要使用extern "C"来说明。
探索C++的秘密之详解extern的更多相关文章
- 探索C++的秘密之详解extern "C",这就是为什么很多.lib被我们正确调用确总是无法解析的。
(转载,绝对的有用) lib被我们正确调用确总是无法解析.这是C++编译和C编译的区别 时常在cpp的代码之中看到这样的代码: #ifdef __cplusplus extern "C&qu ...
- 【转】探索C++的秘密之详解extern
本文转自:http://i.cnblogs.com/EditPosts.aspx?opt=1 时常在cpp的代码之中看到这样的代码: #ifdef __cplusplus extern "C ...
- (转)探索C++的秘密之详解extern "C",这就是为什么很多.lib被我们正确调用确总是无法解析的。
(转载,绝对的有用) lib被我们正确调用确总是无法解析.这是C++编译和C编译的区别 时常在cpp的代码之中看到这样的代码: #ifdef __cplusplus extern "C&qu ...
- 探索c#之一致性Hash详解
阅读目录: 使用场景 算法原理 虚拟节点 代码示例 使用场景 以Redis为例,当系统需要缓存的内容超过单机内存大小时,例如要缓存100G数据,单机内存仅有16G时.这时候就需要考虑进行缓存数据分片, ...
- Webpack探索【5】--- plugins详解
本文主要讲plugins相关内容. https://gitbook.cn/gitchat/column/59e065f64f7fbe555e479204/topic/59e96d87a35cf44e1 ...
- Webpack探索【3】--- loader详解
本文主要说明Webpack的loader相关内容.
- Webpack探索【12】--- externals详解
本文主要讲externals相关内容. https://segmentfault.com/a/1190000012113011
- Mysql探索之Explain执行计划详解
前言 如何写出效率高的SQL语句,提到这必然离不开Explain执行计划的分析,至于什么是执行计划,如何写出高效率的SQL,本篇文章将会一一介绍. 执行计划 执行计划是数据库根据 SQL 语句和相关表 ...
- Dom探索之基础详解
认识DOM DOM级别 注::DOM 0级标准实际并不存在,只是历史坐标系的一个参照点而已,具体的说,它指IE4.0和Netscape Navigator4.0最初支持的DHTML. 节点类型 注:1 ...
随机推荐
- win10操作系统 64位 原版 百度网盘下载
iso镜像文件4.57G,这里压缩成两个两个包便于上传网盘: 使用时候,直接下载两个压缩包解压成镜像文件便可安装: 链接:https://pan.baidu.com/s/1JNgxuBzdzFpp-p ...
- flask中的目录解析
首先我们看一下博客blog的封面,flask和django都属于web框架.不过flask属于轻量级web框架,功能的实现是通过扩展实现的,extension.py 中存放各个对象,具体的功能通过对象 ...
- 20175203 2018-2019-2《Java程序设计》第五周学习总结
20175203 2018-2019-2<Java程序设计>第五周学习总结 第六章:接口与实现 本周学习了<Java程序设计>第六章的内容:接口与实现,以下为本周学习总结. 知 ...
- 二级域名解析设置及Apache 子域名配置
域名管理解析项 如: cy.wanggangg.top 为wanggangg.top域名添加解析 主机记录设为 cy 记录值 为服务器ip地址 打开apache配置文件 新增如下:<Virtua ...
- 数据库(二)—— MySQL索引优化
目录 MySQL的索引优化 一.MySQL 5.7的初始化配置 二.MySQL配置文件 1.配置 2.配置文件作用 三.多实例 1.创建相关的目录 2.创建实例的配置文件 3.初始化 4.授权 5.启 ...
- vue PC端页面引入vue-quill-editor富文本插件
项目需要:在添加新类别的弹框中,要在输入框中输入多条描述信息,不同的描述信息要换行输入,输入后点击确定传给后端,接口返回成功后点击查看刚添加的新类别时,描述框中展现多条换行的描述信息也要跟填写时一样( ...
- 将arcEngine9.3和dev9.2.4开发的项目升级成arcObject10.2和dev15.1.3过程中遇到的问题和解决
好久没碰.net了,arcgis更是感觉都忘干净了,今天将arcEngine9.3和dev9.2.4开发的一个项目升级成arcObject10.2和dev15.1.3过程中遇到了一系问题,留个笔记,留 ...
- maven spring-mvc mybatis整合
一 首先在myeclipse中安装好maven插件. 1.下载地址:http://mirror.bit.edu.cn/apache/maven/maven-3/3.0.5/binaries/apach ...
- Git版本控制及gitlab私有仓库
Git版本控制系统 版本控制系统简介 版本控制系统是一种记录一个或若干个文件内容变化,以便将来查阅特定版本内容情况的系统 记录文件的所有历史变化 随时恢复到任何一个历史状态 多人协作开发 常见版本管理 ...
- Raid,分区表与LVM逻辑卷
1.组Raid 磁盘前512K组合 前446K:MBR引导程序 中64K:分区表 后2K:校检码 Raid0:极致的读写速度,一个数据分散到多个盘去读写.但是极不安全,一旦坏了一块盘那么所有盘都将无法 ...