一、extern "C"

C/C++的代码要混合使用,肯定要用到extern "C"了。extern "C"暗示编译器,被它修饰的内容使用C的链接风格,什么意思呢,直接上代码:

 1 //sample.cpp
 2
 3 void fun(int a)
 4 {
 5 }
 6
 7 void fun(int a, double b)
 8 {
 9 }
10
11 extern "C" void foo(int a)
12 {
13 }

这里有三个函数,首先是重载的两个fun函数,然后是用extern "C"修饰的foo函数。用g++编译一下,然后查看下导出的符号:

发现了吧,两个fun函数编译后导出的符号是前缀"_Z3"加上函数名,再依次加上参数类型的简写。所以void fun(int a)变成了_Z3funi,void fun(int a, double b)变成了_Z3funid。这样做是为了支持函数重载,即,只要参数不同就可以认为是不同的函数。而用extern "C"修饰的函数foo,编译后导出的符号仅仅只是函数名。这就是C的链接风格,当然这样函数重载也就没办法支持了。

用了extern "C",使得无论是C还是C++的代码,编译过后针对同一个函数使用相同的符号,这样链接到一起的时候就不会报“undefined reference"了。实际使用时有两种场合,要么是C++代码调用C代码,要么是C代码调用C++代码。

顺便提一下,extern "C"只能写在C++代码中,C编译器是不认的。

二、C++调用C

还是直接看示例代码清晰明了:

 1 //caller.cpp
 2
 3 #include <iostream>
 4
 5 using namespace std;
 6
 7 extern "C" void fun(void);
 8
 9 int main()
10 {
11     cout << "I'm caller.." << endl;
12     fun();
13 }

1 //fun.c
2
3 #include <stdio.h>
4
5 void fun(void)
6 {
7     printf("This is C function \"fun()\"\n");
8 }

这样两个文件,简单编译运行一下:

当然,如果把extern "C" void fun(void);放到头文件中风格会更好。本人比较懒,这里的简单示例就不按规矩写了。

三、C调用C++

这部分写了两个例子,首先是调用C++的普通函数,然后是调用类成员函数。

同样看代码,不过,先看一下被调用者C++代码:

 1 //fun.cpp
 2
 3 #include <iostream>
 4 using namespace std;
 5
 6 void fun(int a)
 7 {
 8     cout << "This is cpp function \"fun(" << a << ")\"" << endl;
 9 }
10
11 void fun(int a, double b)
12 {
13     cout << "This is cpp function \"fun(" << a << ", " << b << ")\"" << endl;
14 }
15
16 extern "C" void foo(int a)
17 {
18     cout << "This is cpp function \"foo(" << a << ")\"" << endl;
19 }
20
21 extern "C" {
22
23 void fun_i(int a)
24 {
25     fun(a);
26 }
27
28 void fun_d(int a, double b)
29 {
30     fun(a, b);
31 }
32
33 }

这里有5个函数,两个重载的fun函数,剩下三个函数foo, fun_i, fun_d全都用extern "C"修饰了,导出给C代码调用。关于extern "C"的两种写法,一目了然,我就不解释了。这里的fun_i和fun_d只是把fun的两个重载版本分别包装了一下,因为C是没有函数重载的概念的。foo没有重载,所以也没有包装函数。事实上,如果知道C++编译器命名符号的规则(本文一开始已讨论过),不用extern "C",不用包装函数,直接使用符号调用也是可以的。这种方式在下面caller.c中也有示范:

 1 //caller.c
 2
 3 #include <stdio.h>
 4
 5 int main(int argc, const char *argv[])
 6 {
 7     printf("I'm C caller...\n");
 8
 9     fun_i(1);
10     fun_d(2, 2.1);
11     foo(3);
12
13     _Z3funi(4);
14     _Z3funid(5, 5.1);
15
16     return 0;
17 }

编译运行:

可见,用包装函数调用和用符号调用都可以工作。我这里链接了libstdc++库,因为我是用gcc编译的,如果用的是g++,libstdc++是会默认链接的。这就涉及到项目主体是C还是C++的问题了,如果主体是C代码,必须用gcc编译,但是又引用了C++写的库,这时候链接一定要加上libstdc++。反之,如果主体是C++,用g++编译不会有类似的问题。

下面再提供一个用C代码调用C++类成员函数的例子,用包装函数:

 1 //fun.cpp
 2
 3 #include <iostream>
 4 using namespace std;
 5
 6 class shit
 7 {
 8     public:
 9         shit(){}
10         ~shit(){}
11         void happen();
12 };
13
14 void shit::happen()
15 {
16     cout << "Holy shit!!" << endl;
17 }
18
19 extern "C"
20 void run()
21 {
22     shit fresh_shit;
23     fresh_shit.happen();
24 }

 1 //caller.c
 2
 3 #include <stdio.h>
 4
 5 int main(int argc, const char *argv[])
 6 {
 7     printf("I'm C caller...\n");
 8     run();
 9
10     return 0;
11 }

编译运行:

转载于:https://www.cnblogs.com/suosuopuo/p/3388748.html

C/C++代码的混合使用相关推荐

  1. Applet中签名与未签名代码的混合使用带来的问题

    Java Applet如果需要访问本地的受限资源,需要对访问的代码进行数字签名才能进行.Java SE 19 release或者以后的版本为了Applet的安全性,当所执行的Applet代码既包括已签 ...

  2. svn如何隐藏代码路径_程序员课堂—如何通过改善代码风格来消灭隐藏bug

    写在前面:一名有三年Android开发经验的女程序员(欢迎大家关注我 ~期待和大家一起交流和学习Android的相关知识) 正如食物腐烂之前,可能会发出异味.当代码存在隐藏问题时,代码也会表现出一些异 ...

  3. 老码农绝密:使用 TS(TypeScript) 的 10 大理由

    最近,小编读了一篇名为<放弃 TypeScript 的 7 个非常好的理由>,这篇文章的阅读量不低.里面有些观点确实有趣,不过在这里我要向你介绍使用 TypeScript 的 10 个理由 ...

  4. python输入语句-python输入语句

    广告关闭 2017年12月,云+社区对外发布,从最开始的技术博客到现在拥有多个社区产品.未来,我们一起乘风破浪,创造无限可能. python条件语句目录:1. 分支语句(if...else...)2. ...

  5. python与excel表格-超简单:用Python让Excel飞起来

    超简单:用Python让Excel飞起来 作者:王秀文;郭明鑫;王宇韬 编著 出版日期:2020年07月 文件大小:20.30M 支持设备: ¥45.00在线试读 适用客户端: 言商书局 iPad/i ...

  6. 【eoe教程】Android中自定义视图的绘制方法

    原文链接 :http://android.eoe.cn/topic/ui 自定义视图最重要的部分是它的外观.你可以根据应用的需求简单或复杂的实现它. 这个教程包含了最常见的操作. 重写onDraw() ...

  7. 欢迎参与Java 事务讨论

    欢迎参与Java 事务讨论 bruce http://www.jdon.com Jul 14, 2003 6:13 AM 回复 ***************************** **JTA与 ...

  8. python怎么判断是不是汉字危机_谈 Python 的中文编码处理

    最近业务中需要用 Python 写一些脚本.尽管脚本的交互只是命令行 + 日志输出,但是为了让界面友好些,我还是决定用中文输出日志信息. 很快,我就遇到了异常: Python代码   UnicodeE ...

  9. python打造excel神器_超简单:用Python让Excel飞起来

    前言 如何获取学习资源 章Python快速上手 1.1为什么要学习用Python控制Excel 1.2Python编程环境的搭建 1.2.1安装Python官方的编程环境IDLE 1.2.2安装与配置 ...

最新文章

  1. Build-dep linux 知乎,删除通过apt-get build-dep安装的软件包
  2. 12.10 Nginx访问日志 12.11 Nginx日志切割 12.12 静态文件不记录日志和过期时间
  3. Java web(2012/2/23)
  4. wpf mvvm框架_[Windows] 在 Microsoft Docs 网站中挖掘 MVVM 的各种学习资源
  5. html表格宽度拖拽,原生js实现 拖拽改变 table表格列宽
  6. StretchDIBits函数隐含的图像坐标系设置
  7. 出身平凡的郭盛华,究竟是如何逆袭成为传奇人物的?
  8. C语言半框,如何挑选适合自己的镜框(镜片)?
  9. 玩游戏用云电脑选高配有延迟吗
  10. 一款兼容Arduino的模拟TDS传感器
  11. iphone视频照片恢复
  12. 创建OMF(Oracle Managed Files,Oracle管理的文件)
  13. 当你凝视深渊时,深渊也在凝视着你。
  14. PHP是TM最美的语言,我的文章是最棒的狗粮
  15. Ceph Cache Tier
  16. Linux下shell脚本的4中执行方式
  17. 2016年度顶级开源创作工具
  18. 五问目标检测Anchor
  19. 糖尿病遗传风险检测挑战赛
  20. 2.3 黑群晖驱动:开启nvme缓存、将nvme缓存作为存储盘 教程

热门文章

  1. 下列符合c语言语法的字符常量是,C语言程序设计(周经亚)选择题练习-chapter 5.doc...
  2. sierra mysql_macOS High Sierra 使用 Homebrew 安装 MYSQL 5.7
  3. 数学之美系列之一:统计语言模型 (Statistical Language Models)
  4. 零件分组pascal程序
  5. BZOJ 4327 [JSOI2012]玄武密码 (AC自动机)
  6. redhat linux下安装oracle10g rac,RedHat 5.5下安装Oracle 10g+RAC
  7. xftp传输文件报错_Xshell+Xftp--Windows平台远程终端解决方案
  8. 用C语言编写小学四则运算程序,用C语言编写生成小学四则运算程序
  9. Bootstrap-Table入门篇
  10. Redis源码解析:14Redis服务器与客户端间的交互