C调用C++(C++封装以及C对其调用)

来源 https://blog.csdn.net/wonengguwozai/article/details/89854781

  相关知识提点:很经典的extern C解释

  编译器:

    gcc和g++编译器区别
      gcc是c语言编译器(也可处理c++);g++是c++编译器
      g++对.c和.cpp文件都当c++处理;gcc对.c文件当作c处理,对.cpp当做c++处理
      g++编译器在使用时其实调用的是gcc编译器
      gcc不能自动链接库文件(.so等),一般用g++来自动链接库文件,要一定使用gcc则需要加上-lstdc++参数(使用libstdc++.so库)
      gcc编译器和g++编译器在编译函数时,在相同调用方式下(如都是用_stdcall),对函数名的修饰方式不一样
    gcc和g++搜索库文件的原则
      头文件如果放在/usr/include/下,库文件放在/lib或/usr/lib或usr/local/lib下编译器会自动发现对应的库
      如果头文件和库文件不在上述位置存放则在编译器编译时需要指定对应依赖的头文件和库文件的位置,否则编译器找不到库文件。指定方式:
        使用-I(大写的i)指定头文件位置
        使用-L指定库文件位置
        使用 -l库名 指定链接的库名
      例子(链接mytest/lib下的libgtd.so库,注意使用-lgtd来指定):g++ test.cpp -o test.txt -L /mytest/lib -lgtd -I /mytest/include
    函数名的修饰:

      含义:函数的名字修饰(Decorated Name)就是编译器在编译期间创建的一个字符串,用来指明函数的定义或原型。LINK程序或其他工具有时需要指定函数的名字修饰来定位函数的正确位置。多数情况下程序员并不需要知道函数的名字修饰,LINK程序或其他工具会自动区分他们。当然,在某些情况下需要指定函数的名字修饰,例如在C++程序中, 为了让LINK程序或其他工具能够匹配到正确的函数名字,就必须为重载函数和一些特殊的函数(如构造函数和析构函数)指定名字装饰。
    几种函数调用约定(__cdecl, __stdcall,__fastcall)

      用法:调用约定说明符放在函数名前,如int __cdecal add(int a, int b);调用约定一定在函数的声明和定义中都指定且需保持一致
      几种调用约定的区别
        函数被调用时参数(尤其形参)的入栈顺序不同
        函数出栈是由调用函数还是由被调函数弹出栈的区别
        函数名的修饰方式不同。函数名的修饰时编译器在编译函数时对函数名进行名称修饰的操作。这对c语言和c++由很大不同,因为c++有同名函数的重载,类的构造和析构函数。
      由于前两种区别由编译器决定,编程者无从干预,所以不再深究。那么对于第三种(函数名的修饰)区别下面主要说明。
    不同编译环境(c和c++环境)下,各调用约定下对函数名修饰原则

      如函数为:int functionname(int a, int b)

        c环境下

          __cdecl对函数名的修饰:__functionname
          __stdcall对函数名的修饰:_functionname@number(number为形参的字节数)
          __fastcall对函数的修饰:@functionname@number(number为形参的字节数)
        c++环境下(为了重载、继承特性)

          以“?”标识函数名的开始,后跟函数名

          如果是__cdecal调用约定,函数名后面接“@@YA”标识参数表的开始;如果是__stdcall调用约定,函数名后面接“@@YG”标识参数表的开始;如果是__fastcall调用约定,函数名后面接“@@YI”标识参数表的开始。

          后面再跟参数表,参数表以代号表示(各代号的含义后面说明),参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前;

          参数表后以“@Z”标识整个名字的结束,如果该函数无参数,则以“Z”标识结束。

          参数表代号说明

X--void ,
D--char,
E--unsigned char,
F--short,
H--int,
I--unsigned int,
J--long,
K--unsigned long,
M--float,
N--double,
_N--bool,
PA--指针,如果PA表示的是类对象的指针,则PA后接“V+类名+@@”

          那么上面的functionname函数在__cdecal调用约定下编译出的函数名修饰为?add@@YAHHH@Z其余不再列举。

      note: VS中编译C++程序时,编译器自动定义了一个预处理名字__cplusplus,而编译标准C时,自动定义名字__STDC__

    Linux下C调用C++库(首先要对C++封装成C)实例:

      实例链接
      实例说明:
        生成的libadd.so、mylib.so、main.bin缺一不可(因为时动态库),其中libadd.so是原始c++的实现库,而mylib.so是c对c++封装后的库,main.bin是最终的可执行程序。
        勘误:mylib.so的编译命令中-la 应为-ladd,即链接上libadd.so库。
        如果没有按照例子中将libadd.so放到/usr/lib/下,则在编译mylib.so库时应该先指定动态库环境变量LD_LIBRARY_PATH的值(libadd.so的位置)。

C语言封装 C++的类

来源 https://blog.csdn.net/caspiansea/article/details/9676153

本文给出了一种方法。基本思想是,写一个 wrapper文件,把 C++类封装起来,对外只提供C语言的接口,和 C++i相关的都在  wrapper的实现文件里实现。

1. apple.h

#ifndef __APPLE_H__
#define __APPLE_H__ class Apple
{
public:
Apple();
int GetColor(void);
void SetColor(int color); private:
int m_nColor;
};
#endif

apple.cpp

#include "apple.h"

Apple::Apple() : m_nColor()
{
} void Apple::SetColor(int color)
{
m_nColor = color;
} int Apple::GetColor(void)
{
return m_nColor;
}

2. AppleWrapper.h

#ifndef _APPLE_WRAPPER_H__
#define _APPLE_WRAPPER_H_ #ifdef __cplusplus
extern "C" {
#endif struct tagApple; // Warning: 不能使用 extern 修饰 extern struct tagApple *GetInstance(void);
extern void ReleaseInstance(struct tagApple **ppInstance);
extern void SetColor(struct tagApple *pApple, int color);
extern int GetColor(struct tagApple *pApple); #ifdef __cplusplus
};
#endif #endif

AppleWrapper.cpp

#include "AppleWrapper.h"
#include "apple.h" #ifdef __cplusplus
extern "C" {
#endif struct tagApple
{
Apple apple;
}; struct tagApple *GetInstance(void)
{
return new struct tagApple;
} void ReleaseInstance(struct tagApple **ppInstance)
{
delete *ppInstance;
*ppInstance = ;
} void SetColor(struct tagApple *pApple, int color)
{
pApple->apple.SetColor(color);
} int GetColor(struct tagApple *pApple)
{
return pApple->apple.GetColor();
} #ifdef __cplusplus
};
#endif

3. test.c

#include "AppleWrapper.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h> int main(void)
{
struct tagApple * pApple;
pApple = GetInstance();
SetColor(pApple, );
printf("color = %d\n", GetColor(pApple));
ReleaseInstance(&pApple);
assert(pApple == );
return ;
}

可以用 GCC编译:

g++ -g -c apple.cpp  AppleWrapper.cpp
gcc -g test.c -o test AppleWrapper.o apple.o -lstdc++

其实,  wrapper里的 struct 完全可以不要,定义一个  handle更好:

AppleWrapper.h

#ifndef _APPLE_WRAPPER_H__
#define _APPLE_WRAPPER_H_ #ifdef __cplusplus
extern "C" {
#endif extern int GetInstance(int * handle);
extern void ReleaseInstance(int *handle);
extern void SetColor(int handle, int color);
extern int GetColor(int handle); #ifdef __cplusplus
};
#endif #endif

AppleWrapper.cpp

#include "AppleWrapper.h"
#include "apple.h"
#include <vector> #ifdef __cplusplus
extern "C" {
#endif static std::vector<Apple *> g_appleVector; int GetInstance(int * handle)
{
g_appleVector[] = new Apple; // Error: Segmentation fault (core dumped)
*handle = ;
return ;
} void ReleaseInstance(int *handle)
{
delete g_appleVector[*handle];
*handle = -;
} void SetColor(int handle, int color)
{
g_appleVector[handle]->SetColor(color);
} int GetColor(int handle)
{
return g_appleVector[handle]->GetColor();
} #ifdef __cplusplus
};
#endif

test.c

#include "AppleWrapper.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h> int main(void)
{
int handle = -;
GetInstance(&handle);
SetColor(handle, );
printf("color = %d\n", GetColor(handle));
ReleaseInstance(&handle);
assert(handle == -);
return ;
}

================== End

C调用C++(C++封装以及C对其调用)的更多相关文章

  1. SFTP环境搭建及客户代码调用公共方法封装

    一.背景 在开发应用软件的过程中,广泛使用FTP在各子系统间传送文本数据.但FTP存在安全问题,开放到外网存在安全漏洞,容易被攻击.替换方案是使用SFTP,SFTP提供更高的安全性,当然传输的效率也会 ...

  2. 封装libsvm成可程序调用的C/C++类

    libsvm很早之前就用了,现在封装一下方便自己使用,也方便大家更快的使用这个库,这个库一个挺有用的特性就是对测试样本的概率估计.源码在随笔的最后.liblinear的版本也是类似移植,主要是处理好数 ...

  3. 微信小程序:封装全局的promise异步调用方法

    微信小程序:封装全局的promise异步调用方法 一:封装 function POST(url, params) { let promise = new Promise(function (resol ...

  4. ABP开发框架前后端开发系列---(4)Web API调用类的封装和使用

    在前面随笔介绍ABP应用框架的项目组织情况,以及项目中领域层各个类代码组织,以及简化了ABP框架的各个层的内容,使得我们项目结构更加清晰.上篇随笔已经介绍了字典模块中应用服务层接口的实现情况,并且通过 ...

  5. VBA/VB6/VBS/VB.NET/C#/Python/PowerShell都能调用的API封装库

    API函数很强大,但是声明的时候比较繁琐. 我开发的封装库,包括窗口.键盘.鼠标.消息等常用功能.用户不需要添加API函数的声明,就可以用到API的功能. 在VBA.VB6的引用对话框中引用API.t ...

  6. SpringCloud03 Ribbon知识点、 Feign知识点、利用RestTemplate+Ribbon调用远程服务提供的资源、利用feign调用远程服务提供的资源、熔断

    1 远程服务资源的调用 1.1 古老的套路 在微服务出现之前,所有的远程服务资源必须通过RestTemplate或者HttpClient进行:但是这两者仅仅实现了远程服务资源的调用,并未提供负载均衡实 ...

  7. Don’t Use Accessor Methods in Initializer Methods and dealloc 【初始化和dealloc方法中不要调用属性的存取方法,而要直接调用 _实例变量】

    1.问题:    在dealloc方法中使用[self.xxx release]和[xxx release]的区别? 用Xcode的Analyze分析我的Project,会列出一堆如下的提示:Inco ...

  8. ios调用第三方程序打开文件,以及第三方调用自己的APP打开文件

    1.自己的APP调用第三方打开文件 主要是使用  UIDocumentInteractionController  类   并实现 UIDocumentInteractionControllerDel ...

  9. C++构造函数的自动调用(调用一个父类的构造函数,有显性调用最好,否则就默认调用无参数的构造函数)——哲学思想:不调用怎么初始化父类的成员数据和VMT?

    我总是记不住构造函数的特点,关键还是没有领会那个哲学思想:父类的构造函数一方面要初始化它自己的成员数据,另一方面也要建立它自己的VMT呀!心里默念一百遍:一定调用父类构造函数,一定调用父类构造函数,一 ...

随机推荐

  1. Flutter中用ListView嵌套GridView报错异常

    flutter中的ListView组件和GridView组件都是常用的布局组件,有时候ListView中需要嵌套GridView来使用,例如下图: 这种情况就需要在ListView里面再嵌套一个Gri ...

  2. arcgis python 获得表字段的唯一值

    #获得唯一值 by gisoracle def getuniqueValue(inTable,inField): rows = arcpy.da.SearchCursor(inTable,[inFie ...

  3. Csdn账号如何注销?

    Csdn账号如何注销?   请在ios端app设置内注销 ios端注销在设置页面的底部左下角,andriod在2019.07月底更新,即可支持   文章来源:刘俊涛的博客 欢迎关注,有问题一起学习欢迎 ...

  4. MySQL索引选择及添加原则

    索引选择性就是结果个数与总个数的比值. 用sql语句表示为: SELECT COUNT(*) FROM table_name WHERE column_name/SELECT COUNT(*) FRO ...

  5. C++重写(覆盖)、重载、重定义、多态

    1 重写(覆盖)override override是重写(覆盖)了一个方法,以实现不同的功能.一般用于子类在继承父类时,重写(覆盖)父类中的方法.函数特征相同,但是具体实现不同. 重写需要注意: 被重 ...

  6. CDH构建大数据平台-Kerberos高可用部署【完结篇】

    CDH构建大数据平台-Kerberos高可用部署[完结篇] 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.  一.安装Kerberos相关的软件包并同步配置文件 1>.实验环境 ...

  7. Mac OS xshell xftp 替代工具-finalshell

    安装步骤: 1,打开Mac 终端: 2,输入: curl -L -o finalshell_install.sh www.hostbuf.com/downloads/finalshell_instal ...

  8. hashMap 底层原理+LinkedHashMap 底层原理+常见面试题

    1.源码 java1.7    hashMap 底层实现是数组+链表 java1.8 对上面进行优化  数组+链表+红黑树 2.hashmap  是怎么保存数据的. 在hashmap 中有这样一个结构 ...

  9. 用jeecg做个项目第三讲(自定义导入导出)

    1.导入 前端js和跳转页面 <t:dgToolBar title="导入单一模板" icon="icon-put" funname="Impo ...

  10. 阶段5 3.微服务项目【学成在线】_day03 CMS页面管理开发_14-异常处理-异常处理的问题分析

    这块代码没有异常处理.如果在Service出现了异常代码,在哪里捕获?要么在Servive内捕获,要么在调用service的地方也就是controller内捕获 每个调用service的地方都要去捕获 ...