c++通常被称为Better c,多数是因为c++程序可以很简单的调用c函数,语法上基本实现兼容。最常用的调用方式就是c++模块调用c实现的dll导出函数,很简单的用法,使用extern "C"将c头文件或者函数修饰下。

本文主要涉及到在c模块中如何调用c++函数,或者换个名字,extern "C"在c语言中的功能介绍

c++中的extern "C"

通常,我们在需要调用c函数或者c实现的模块时,需要使用extern "C"修饰下对应的部分代码,告诉c++编译器按照c的调用规约调用相关模块代码。常见的形式如下:

  1. extern "C"
  2. {
  3. // ffmpeg public header
  4. #include "avutil.h"
  5. #incluee "avcodec.h"
  6. // 函数声明,以c语言调用
  7. int Func(int param);
  8. }

c语言中的extern "C"

近期在看JNI的调用实现机制,不自觉的在想c能调用c++模块吗?

基本的思路是来在于c++语言提供的extern "C"机制,既然可以在c++中写c模块,ok,那只需要一个中间层就可以让c调用c++的模块。

普通函数调用

在c++实现如下函数:

  1. // in header file(.h)
  2. extern "C" int FunCppDecorate(int param);
  3. // in implenmentation file(.cpp)
  4. int FunCppDecorate(int param)
  5. {
  6. printf("decorating by extern c, you have rights to invoke cpp function in c\nwith input %d\n"
  7. , param);
  8. return (param + 1);
  9. }

在c中按照下面方式调用

  1. // declaration
  2. int FunCppDecorate(int param);
  3. // invoke
  4. FunCppDecorate(1);

重载函数调用

由于c不支持重载函数,如果需要c调用c++重载函数需要显式的给出调用的方式,并在c声明时给出对应对应机制。

在c++实现如下函数:

  1. // in header file(.h)
  2. void OverloadFunc(int param, bool is_c=false);
  3. void OverloadFunc(double param, bool is_c=false);
  4. extern "C"
  5. {
  6. void OverloadDecorate_i(int param);
  7. void OverloadDecorate_d(double param);
  8. }
  9. // in implenmentation file(.cpp)
  10. // ...
  11. void OverloadDecorate_i(int param)
  12. {
  13. OverloadFunc(param, true);
  14. }
  15. void OverloadDecorate_d(double param)
  16. {
  17. OverloadFunc(param, true);
  18. }

在c中按照下面方式调用

  1. // declaration
  2. void OverloadDecorate_i(int param);
  3. void OverloadDecorate_d(double param);
  4. // invoke
  5. OverloadDecorate_i(1);
  6. OverloadDecorate_d(2.0);

类成员函数的调用

由于c++中类具有特殊的编译器附加的构造和析构函数,为了在c中可以访问c++的类,需要做一些c++编译器实现的功能,比如对象的构造和析构。c不能直接使用class名称,需要使用struct作为中转。实现调用如下:

  1. // in header file(.h)
  2. class AType
  3. {
  4. public:
  5. AType();
  6. ~AType();
  7. void MemFunc(int value);
  8. };
  9. extern "C"
  10. {
  11. struct TagAType * CreateInstance();
  12. void DestoryInstance(struct TagAType ** atype);
  13. void ClassMemFunc(struct TagAType * pthis, int param);
  14. }
  15. // in implenmentation file(.cpp)
  16. // ...
  17. extern "C" struct TagAType
  18. {
  19. AType a;
  20. };
  21. struct TagAType * CreateInstance()
  22. {
  23. return (TagAType*)malloc(sizeof(TagAType));
  24. }
  25. void DestoryInstance(struct TagAType ** atype)
  26. {
  27. if (NULL != atype && NULL != *atype)
  28. {
  29. free(*atype);
  30. atype = NULL;
  31. }
  32. }
  33. void ClassMemFunc(struct TagAType * pthis, int param)
  34. {
  35. if(NULL != pthis)pthis->a.MemFunc(param);
  36. }

在c中按照下面方式调用

  1. // declaration
  2. struct TagAType;
  3. struct TagAType * CreateInstance();
  4. void DestoryInstance(struct TagAType ** atype);
  5. void ClassMemFunc(struct TagAType * pthis, int param);
  6. // invoke
  7. struct TagAType * obj = CreateInstance();
  8. ClassMemFunc(obj, 12);
  9. DestoryInstance(&obj);

小结

相关代码可以从我的git下载:https://git.oschina.net/Tocy/SampleCode.git ,位于c_c++目录下,名字前缀为1-c-invoke-cpp*。

其中四个文件,1-c-invoke-cpp.cpp(h)是c++中的实现文件(头文件),1-c-invoke-cpp-main.c(h)是c中的实现文件(头文件),其中包含主函数的测试代码。

编译和运行命令可以参考如下:

g++ -c 1-c-invoke-cpp.cpp

gcc -c 1-c-invoke-cpp-main.c

gcc 1-c-invoke-cpp.o 1-c-invoke-cpp-main.o -o invoke.exe

invoke

pause

针对c++实现中的extern "C"修饰符的作用,可以使用nm命令查看.o文件的输出格式,这是我使用gcc编译后的输出

nm 1-c-invoke-cpp.o

...

00000000000000ac T _Z12OverloadFuncdb

0000000000000041 T _Z12OverloadFuncib

0000000000000000 T _Z6printfPKcz

0000000000000000 T _Z8DenyFuncv

0000000000000168 T _ZN5AType7MemFuncEi

0000000000000150 T _ZN5ATypeC1Ev

0000000000000150 T _ZN5ATypeC2Ev

000000000000015c T _ZN5ATypeD1Ev

000000000000015c T _ZN5ATypeD2Ev

00000000000001e4 T ClassMemFunc

000000000000018f T CreateInstance

00000000000001a7 T DestoryInstance

U free

000000000000001b T FunCppDecorate

U malloc

000000000000012c T OverloadDecorate_d

000000000000008d T OverloadDecorate_i

从上面输出可以明显看出c++和c的函数编译之后的修饰规则是不同的。

c与c++相互调用机制分析与实现的更多相关文章

  1. Android群英传》读书笔记 (4) 第八章 Activity和Activity调用栈分析 + 第九章 系统信息与安全机制 + 第十章 性能优化

    第八章 Activity和Activity调用栈分析 1.Activity生命周期理解生命周期就是两张图:第一张图是回字型的生命周期图第二张图是金字塔型的生命周期图 注意点(1)从stopped状态重 ...

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

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

  3. C语言栈调用机制初探

    学习linux离不开c语言,也离不开汇编,二者之间的相互调用在源代码中几乎随处可见.所以必须清楚地理解c语言背后的汇编结果才能更好地读懂linux中相关的代码.否则会有很多疑惑,比如在head.s中会 ...

  4. Hybrid App开发模式中, IOS/Android 和 JavaScript相互调用方式

    IOS:Objective-C 和 JavaScript 的相互调用 iOS7以前,iOS SDK 并没有原生提供 js 调用 native 代码的 API.但是 UIWebView 的一个 dele ...

  5. Python实例浅谈之三Python与C/C++相互调用

    一.问题 Python模块和C/C++的动态库间相互调用在实际的应用中会有所涉及,在此作一总结. 二.Python调用C/C++ 1.Python调用C动态链接库 Python调用C库比较简单,不经过 ...

  6. Linux 线程实现机制分析 Linux 线程模型的比较:LinuxThreads 和 NPTL

    Linux 线程实现机制分析 Linux 线程实现机制分析  Linux 线程模型的比较:LinuxThreads 和 NPTL http://www.ibm.com/developerworks/c ...

  7. C&C++——C函数与C++函数相互调用问题

    C C++相互调用 在项目中融合C和C++有时是不可避免的,在调用对方的功能函数的时候,或许会出现这样那样的问题,但只要我的C代码和我的C++代码分别都能成功编译,那其他就不是问题.近来在主程序是C语 ...

  8. Python与C/C++相互调用(python2 调c++那个试了ok)

    一.问题 Python模块和C/C++的动态库间相互调用在实际的应用中会有所涉及,在此作一总结. 二.Python调用C/C++ 1.Python调用C动态链接库 Python调用C库比较简单,不经过 ...

  9. Python与C/C++相互调用(转)

    原文链接 作者 一.问题 Python模块和C/C++的动态库间相互调用在实际的应用中会有所涉及,在此作一总结. 二.Python调用C/C++ 1.Python调用C动态链接库 Python调用C库 ...

随机推荐

  1. Python中的两种路径

    Java中有两种路径,一种是操作系统的路径path,另一种是类路径classpath. Python中也是如此,一种是操作系统环境变量中的path,另一种是PYTHONPATH. 当import xx ...

  2. 百度地图 ijintui以及七牛、百度编辑器、kindeditor

    密码是明文存储的 sig错误是因为params没拼接上md5后的秘钥,测试时候可以在 Api\Controller\CommonController\_initialize 方法里注释掉效验的代码 代 ...

  3. webpack window 添加ES6支出

    著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:张轩链接:http://zhuanlan.zhihu.com/p/20367175来源:知乎 如果现在你的项目还没有对ES6的 ...

  4. mysql5.7忘记密码时,修改root密码

    (1).由于MySQL5.7在安装完后,第一次启动时,会在root目录下生产一个随机的密码,文件名为 .mysql_secret 所以,登录时需要用随机密码登录,然后通过以下命令修改密码 “SET P ...

  5. <welcome-file>index.action</welcome-file>直接设置action,404和struts2中的解决方案

    这几天的项目页面的访问全部改为.action访问,在修改首页时遇到了问题.将web.xml文件中<welcome-file>index.action</welcome-file> ...

  6. 一个web.Config或app.Config自定义段configSections的示例

    一个web.Config或app.Config自定义段configSections的示例 越来越觉得,直接用配置文件app.Config或web.Config配置应用系统的运行参数,比自己做一个xml ...

  7. React icon bak

  8. 基于key/value+Hadoop HDFS 设计的存储系统的shell命令接口

    对于hadoop HDFS 中的全部命令进行解析(当中操作流程是自己的想法有不允许见欢迎大家指正) 接口名称 功能 操作流程 get 将文件拷贝到本地文件系统 . 假设指定了多个源文件,本地目的端必须 ...

  9. SharePoint 2013 Troubleshooting——启用 Developer Dashboard

    SharePoint 2010的管理员和开发者可能对SharePoint Developer Dashboard(开发人员仪表盘)很熟悉.在SharePoint 2013这个工具已经被大范围的改写了, ...

  10. virtualbox 最小化安装centos7 配置双网卡(nat和桥接)记录----已经过期

    该文章已经过期   请参考另一篇文章:virtualbox 安装centos7 配置桥接网卡,实现主机和虚拟机互通,虚拟机可以访问外网,解决无法上网问题   先说明一下为什么要配置双网卡? 配置nat ...