C调用C++(C++封装以及C对其调用)
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对其调用)的更多相关文章
- SFTP环境搭建及客户代码调用公共方法封装
一.背景 在开发应用软件的过程中,广泛使用FTP在各子系统间传送文本数据.但FTP存在安全问题,开放到外网存在安全漏洞,容易被攻击.替换方案是使用SFTP,SFTP提供更高的安全性,当然传输的效率也会 ...
- 封装libsvm成可程序调用的C/C++类
libsvm很早之前就用了,现在封装一下方便自己使用,也方便大家更快的使用这个库,这个库一个挺有用的特性就是对测试样本的概率估计.源码在随笔的最后.liblinear的版本也是类似移植,主要是处理好数 ...
- 微信小程序:封装全局的promise异步调用方法
微信小程序:封装全局的promise异步调用方法 一:封装 function POST(url, params) { let promise = new Promise(function (resol ...
- ABP开发框架前后端开发系列---(4)Web API调用类的封装和使用
在前面随笔介绍ABP应用框架的项目组织情况,以及项目中领域层各个类代码组织,以及简化了ABP框架的各个层的内容,使得我们项目结构更加清晰.上篇随笔已经介绍了字典模块中应用服务层接口的实现情况,并且通过 ...
- VBA/VB6/VBS/VB.NET/C#/Python/PowerShell都能调用的API封装库
API函数很强大,但是声明的时候比较繁琐. 我开发的封装库,包括窗口.键盘.鼠标.消息等常用功能.用户不需要添加API函数的声明,就可以用到API的功能. 在VBA.VB6的引用对话框中引用API.t ...
- SpringCloud03 Ribbon知识点、 Feign知识点、利用RestTemplate+Ribbon调用远程服务提供的资源、利用feign调用远程服务提供的资源、熔断
1 远程服务资源的调用 1.1 古老的套路 在微服务出现之前,所有的远程服务资源必须通过RestTemplate或者HttpClient进行:但是这两者仅仅实现了远程服务资源的调用,并未提供负载均衡实 ...
- Don’t Use Accessor Methods in Initializer Methods and dealloc 【初始化和dealloc方法中不要调用属性的存取方法,而要直接调用 _实例变量】
1.问题: 在dealloc方法中使用[self.xxx release]和[xxx release]的区别? 用Xcode的Analyze分析我的Project,会列出一堆如下的提示:Inco ...
- ios调用第三方程序打开文件,以及第三方调用自己的APP打开文件
1.自己的APP调用第三方打开文件 主要是使用 UIDocumentInteractionController 类 并实现 UIDocumentInteractionControllerDel ...
- C++构造函数的自动调用(调用一个父类的构造函数,有显性调用最好,否则就默认调用无参数的构造函数)——哲学思想:不调用怎么初始化父类的成员数据和VMT?
我总是记不住构造函数的特点,关键还是没有领会那个哲学思想:父类的构造函数一方面要初始化它自己的成员数据,另一方面也要建立它自己的VMT呀!心里默念一百遍:一定调用父类构造函数,一定调用父类构造函数,一 ...
随机推荐
- WIN7+Qt5.2.0连接oracle数据库的oci驱动的编译
一.前提安装 1.需要安装QT5.2.0,本介绍安装的是qt-windows-opensource-5.2.0-mingw48_opengl-x86-offline.exe: 本文安装目录:c:\Qt ...
- iview -- vue modal 显示到最顶层 层级
给想要显示到顶层的modal 设置class属性 .my-modal-parent { position: fixed; // 浮动 z-index:; }
- 【Java/MySql】使用JDBC访问MySql数据库的Maven工程
下载链接:https://files.cnblogs.com/files/xiandedanteng/FindNotnullColumns20191102-1.rar pom.xml里写: <p ...
- Xshell查看日志
查询日志命令(复制后鼠标右键粘贴): tail -1000f /mnt/logs/SMFManagement/SMFManagement_info.log
- Facebook币Libra学习-4.新的智能合约语言Move入门
Move是一种新的编程语言,旨在为Libra Blockchain提供安全可编程的基础.Libra Blockchain中的帐户是任意数量的Move资源和Move模块的容器.提交给Libra Bloc ...
- spring中的原型模式
大家好,我原本是神剑山庄的铸剑师,名叫小赵,本来干的好好的,后来一时兴起,睡了三少爷的小姨子,与其一直提心吊胆,干脆来个逃之夭夭. 但是,我也要吃饭的呀,工作也得找,神剑山庄去不得,还有断剑山庄.藏剑 ...
- 一步一步搭建Nuget私服
大致流程:1. 通过VS创建一个Web空项目,然后通过Nuget引入Nuget.Server(目前最新版3.2.1).2. 直接将这个Web项目发布到IIS.3. 通过nuget.exe打包*.nup ...
- c++后台开发面试常见知识点总结(一)c++基础
指针和引用的区别 extern,const,static,volatile关键字 #define 和const的区别 关于typedef和#define; C++程序中内存使用情况分析(堆和栈的区别) ...
- Oracle查询显示CLOB的内容
select dbms_lob.substr(note) from table
- rabbitmq-BasicReject
拒收,是接收端在收到消息的时候响应给RabbitMQ服务的一种命令,告诉服务器不应该由我处理,或者拒绝处理,扔掉.接收端在发送reject命令的时候可以选择是否要重新放回queue中.如果没有其他接收 ...