在项目中融合C和C++有时是不可避免的,在调用对方的功能函数的时候,或许会出现这样那样的问题。
近来在主程序是C语言,而调用C++功能函数的时候,C++的*.h头文件都能找到,功能函数也都定义了,最重要的是,单独编译C++的时候完全没有问题,
但当用主程序的C调用C++的功能函数时总是提示该函数未定义(undefined)。这是什么问题?如何解决?

关键点在这里:我们就靠在C++的*.h和*.cpp的头尾加入下面代码才得以解决问题。

#ifdef __cplusplus
extern "C" {
#endif
//一段代码
#ifdef __cplusplus
}
#endif

1、#ifdef _cplusplus/#endif _cplusplus及发散
其中 __cplusplus是cpp中的自定义宏,很明显#ifdef/#endif、#ifndef/#endif用于条件编译,
#ifdef _cplusplus/#endif _cplusplus——表示如果定义了宏_cplusplus,就执行#ifdef/#endif之间的语句,否则就不执行。
上面的代码的含义是 : 如果这是一段cpp的代码,那么加入extern "C"{ 和 } 处理其中的代码。
在这里为什么需要#ifdef _cplusplus/#endif _cplusplus呢?因为C语言中不支持extern "C"声明,如果你明白extern "C"的作用就知道在C中也没有必要这样做,这就是条件编译的作用!在.c文件中包含了extern "C"时会出现编译时错误。

2、extern "C"
extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。
通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。
与extern对应的关键字是 static,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被extern “C”修饰。
在C++源文件中的语句前面加上extern "C",表明它按照类C的编译和连接规约来编译和连接,而不是C++的编译的连接规约。这样在类C的代码中就可以调用C++的函数or变量等。
还有要说明的是,extern "C"指令仅指定编译和连接规约,但不影响语义。例如在函数声明中,指定了extern "C",仍然要遵守C++的类型检测、参数转换规则。

3、C和C++互相调用
要明白为何使用extern "C",还得从cpp中对函数的重载处理开始说起。
在c++中,为了支持重载机制,在编译生成的汇编码中,要对函数的名字进行一些处理,加入比如函数的返回类型等等。
而在C中,只是简单的函数名字而已,不会加入其他的信息。也就是说,C++和C对产生的函数名字的处理是不一样的。
加入 extern "C" 声明的目的是解决C与C++的相互调用的问题。

3.1、C++的编译和连接
C++是一个面向对象语言(虽不是纯粹的面向对象语言),它支持函数的重载,重载这个特性给我们带来了很大的便利。为了支持函数重载的这个特性,C++编译器实际上将下面这些重载函数:
void print(int i);
void print(char c);
void print(float f);
void print(char* s);
编译为:
_print_int
_print_char
_print_float
_pirnt_string
这样的函数名,来唯一标识每个函数。注:不同的编译器实现可能不一样,但是都是利用这种机制。所以当连接是调用print(3)时,它会去查找_print_int(3)这样的函数。
下面说个题外话,正是因为这点,重载被认为不是多态,多态是运行时动态绑定(“一种接口多种实现”),如果硬要认为重载是多态,它顶多是编译时“多态”。
C++中的变量,编译也类似,如全局变量可能编译g_xx,类变量编译为c_xx等。连接是也是按照这种机制去查找相应的变量。

3.2、C的编译和连接
C语言中并没有重载和类这些特性,故并不像C++那样print(int i),会被编译为_print_int,而是直接编译为_print等。因此如果直接在C++中调用C的函数会失败,因为连接是调用C中的print(3)时,它会去找_print_int(3)。因此extern "C"的作用就体现出来了。

3.3、C++中调用C的代码
假设一个C的头文件cHeader.h中包含一个函数print(int i),为了在C++中能够调用它,必须要加上extern关键字。
C++程序调用C函数:http://blog.csdn.net/ustcgy/article/details/5063082

3.4、C中调用C++的代码
C程序调用C++函数 : http://blog.csdn.net/ustcgy/article/details/5063243

参考链接:http://www.cnblogs.com/skynet/archive/2010/07/10/1774964.html
http://blog.chinaunix.net/uid-24118190-id-2985318.html

C和C++相互调用的更多相关文章

  1. Android和JavaScript相互调用的方法

    转载地址:http://www.jb51.net/article/77206.htm 这篇文章主要介绍了Android和JavaScript相互调用的方法,实例分析了Android的WebView执行 ...

  2. 多个Activity相互调用和Intent

    MainActivity.java和OtherActivity.java的相互调用 首先MainActivity.java是Android程序自带的,新建一个类OtherActiviy extends ...

  3. JS代码和OC代码的相互调用

    JS调用OC 很多应用里面或多或少的调用了网页,来达到绚丽的效果,所谓的JS调用OC.....举个例子吧,网页上有个按钮 点击按钮跳转界面,跳转的动作由OC的代码实现. OC调用JS 还是举个例子,我 ...

  4. C程序与Lua脚本相互调用

    Lua脚本是一种可用于C程序开发/测试的工具,本篇介绍一下C程序与Lua脚本如何进行相互调用,更加详细的操作参见<Programing in Lua>.本文分为3个部分:1.Windows ...

  5. Unity3D中C#和js方法相互调用

    通过查找资料,Unity3D中C#和js要相互调用彼此的方法,js文件必须放在"Standard Assets". "Pro Standard Assets" ...

  6. Unity3d 脚本相互调用

    unity中三种调用其他脚本函数的方法 第一种,被调用脚本函数为static类型,调用时直接用  脚本名.函数名().很不实用…… 第二种,GameObject.Find("脚本所在物体名& ...

  7. Lua与C++相互调用

    {--1.环境--} 为了快速入手,使用了小巧快速的vc++6.0编译器 以及在官网下载了Lua安装包..官网地址{--http://10.21.210.18/seeyon/index.jsp--} ...

  8. 关于action script与js相互调用的Security Error问题

    大家都知道,as和js相互调用可以通过ExternalInterface.call和ExternalInterface.addCallback来进行. 比较好的做法是使用之前通过ExternalInt ...

  9. Java与.NET 的Web Services相互调用

    一:简介 本文介绍了Java与.NET开发的Web Services相互调用的技术.本文包括两个部分,第一部分介绍了如何用.NET做客户端调用Java写的Web Services,第二部分介绍了如何用 ...

  10. Android消息机制之实现两个不同线程之间相互传递数据相互调用

    目的:实现两个不同线程之间相互传递数据相互调用方法. 线程一中定义mainHandler 并定义一个方法mainDecode 线程二中定义twoHandler 并定义一个方法twoEncode 实现当 ...

随机推荐

  1. 细说shiro之七:缓存

    官网:https://shiro.apache.org/ 一. 概述 Shiro作为一个开源的权限框架,其组件化的设计思想使得开发者可以根据具体业务场景灵活地实现权限管理方案,权限粒度的控制非常方便. ...

  2. gcc 编译 汇编 链接

    要想研究使用 gcc, gcc-multilib 这个包是一定要安装的, 它允许通过 -m32 和 -m64 选项来选择生成 32 位或者 64 的 ELF 文件. 我们知道程序的默认起点是 _sta ...

  3. Java面试题系列(四)强引用、软引用、弱引用、幻象引用有什么区别?

    序言 资料 https://blog.csdn.net/weixin_38729727/article/details/82259507

  4. Java SSM框架之MyBatis3(十)MyBatis批量插入数据(MySql)

    插入成功后返回自增主键 <insert id="insertRole" parameterType="role" useGeneratedKeys=&qu ...

  5. Newtonsoft.Json 的高级用法

    Ø  简介 接着前一篇http://www.cnblogs.com/abeam/p/8295765.html,继续研究 Newtonsoft.Json 的一些高级用法.主要包括: 1.   JSON ...

  6. [C++]PAT乙级1012.数字分类 (20/20)

    /* 1012. 数字分类 (20) 给定一系列正整数,请按要求对数字进行分类,并输出以下5个数字: A1 = 能被5整除的数字中所有偶数的和: A2 = 将被5除后余1的数字按给出顺序进行交错求和, ...

  7. cocos2dx 3.4 测试例 目录

    ActionManager 动作管理Actions-Basic   按引导移动Actions-Ease  缓动Actions-Progress  渐渐显示Allocator-Basic  std 的 ...

  8. CF961G Partitions

    传送门 luogu 显然每个数的贡献可以一起算感性理解一下,于是答案就是权值总和乘以每个数被算了几次 那个"集合大小为\(|S|\)的集合权值为权值和乘\(|S|\)",可以看成一 ...

  9. 将本地时间转换成 UTC 时间,0时区时间

    // 将时间戳转换成日期格式: function timestampToTime(timestamp) { var date = new Date(timestamp);//时间戳为10位需*1000 ...

  10. MySql数据库学习笔记(3)

    查看默认事务隔离级别 mysql> select @@tx_isolation; mysql> select @@global.tx_isolation; mysql> select ...