zoukankan      html  css  js  c++  java
  • 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的函数编译之后的修饰规则是不同的。

  • 相关阅读:
    几个新角色:数据科学家、数据分析师、数据(算法)工程师
    人类投资经理再也无法击败电脑的时代终将到来了...
    Action Results in Web API 2
    Multiple actions were found that match the request in Web Api
    Routing in ASP.NET Web API
    how to create an asp.net web api project in visual studio 2017
    网站漏洞扫描工具
    How does asp.net web api work?
    asp.net web api history and how does it work?
    What is the difference between a web API and a web service?
  • 原文地址:https://www.cnblogs.com/tocy/p/c-cpp-inter-invoke-analysis.html
Copyright © 2011-2022 走看看