• c与c++相互调用机制分析与实现


    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的调用规约调用相关模块代码。常见的形式如下:

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

    c语言中的extern "C"

    近期在看JNI的调用实现机制,不自觉的在想c能调用c++模块吗?
    基本的思路是来在于c++语言提供的extern "C"机制,既然可以在c++中写c模块,ok,那只需要一个中间层就可以让c调用c++的模块。

    普通函数调用

    在c++实现如下函数:

    // in header file(.h)
    extern "C" int FunCppDecorate(int param);
    
    // in implenmentation file(.cpp)
    int FunCppDecorate(int param)
    {
    	printf("decorating by extern c, you have rights to invoke cpp function in c
    with input %d
    "
    			, param);
    	return (param + 1);
    }
    

    在c中按照下面方式调用

    // declaration
    int FunCppDecorate(int param);
    
    // invoke
    FunCppDecorate(1);
    

    重载函数调用

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

    // in header file(.h)
    void OverloadFunc(int param, bool is_c=false);
    void OverloadFunc(double param, bool is_c=false);
    
    extern "C"
    {
    	void OverloadDecorate_i(int param);
    	void OverloadDecorate_d(double param);
    }
    	
    
    // in implenmentation file(.cpp)
    // ...
    void OverloadDecorate_i(int param)
    {
    	OverloadFunc(param, true);
    }
    
    void OverloadDecorate_d(double param)
    {
    	OverloadFunc(param, true);
    }
    

    在c中按照下面方式调用

    // declaration
    void OverloadDecorate_i(int param);
    void OverloadDecorate_d(double param);
    
    // invoke
    OverloadDecorate_i(1);
    OverloadDecorate_d(2.0);
    

    类成员函数的调用

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

    // in header file(.h)
    class AType
    {
    public:
    	AType();
    	~AType();
    	
    	void MemFunc(int value);
    };
    
    extern "C"
    {
    	struct TagAType * CreateInstance();
    	void DestoryInstance(struct TagAType ** atype);
    	void ClassMemFunc(struct TagAType * pthis, int param);
    }
    	
    
    // in implenmentation file(.cpp)
    // ...
    extern "C" struct TagAType
    {
    	AType a;
    };
    
    struct TagAType * CreateInstance()
    {
    	return (TagAType*)malloc(sizeof(TagAType));
    }
    void DestoryInstance(struct TagAType ** atype) 
    {
    	if (NULL != atype && NULL != *atype)
    	{
    		free(*atype);
    		atype = NULL;
    	}
    }
    void ClassMemFunc(struct TagAType * pthis, int param)
    {
    	if(NULL != pthis)pthis->a.MemFunc(param);
    }
    

    在c中按照下面方式调用

    // declaration
    struct TagAType;
    struct TagAType * CreateInstance();
    void DestoryInstance(struct TagAType ** atype);
    void ClassMemFunc(struct TagAType * pthis, int param);
    
    // invoke
    struct TagAType * obj = CreateInstance();
    ClassMemFunc(obj, 12);
    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的函数编译之后的修饰规则是不同的。

  • 相关阅读:
    使用Microsoft URL Rewrite Module for IIS 7.0修改WEB.CONFIG即可实现*.HTML伪静态 无需修改应用程序映射
    我的第二个智能手机 HKC G801 严重质量问题 USB接口坏后解决办法
    JQuery的跨域方法 可跨新浪、腾讯等任意网站
    IIS7下使用MSDNURLRewriting.msi开源组件的设置
    面向对象编程,真离不开设计模式?
    jQuery 的filter(),not(),split()用法
    2008年总结
    程序中 同步和异步的经典解释 (一听就懂)
    2009年元旦前祝福 开心一下
    到底什么是SOA?
  • 原文地址:https://www.cnblogs.com/tocy/p/c-cpp-inter-invoke-analysis.html
Copyright © 2020-2023  润新知