C语言如何封装CPP代码的接口

news2024/11/17 3:28:31

为什么要用C语言封装CPP代码?

C++不是兼容C语言的吗?

是的,如果你只是自己开发程序,只用一种语言的话,就没有必要进行封装。如果你开发的是一个C++的.so库,你希望将这个库提供给其他语言使用的话,就涉及到不同语言的相互调用,大家都知道C语言的库是最容易与其他语言交互的。

比如mysql是用C++编写的,但还会提供C语言的调用接口(.h头文件),但是这个头文件与C++所用的头文件是不一样的,因为C语言处理不 了Class这些东西。

这个文章我们只讲如何在C语言中调用C++代码。

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

如何封装。

提供一个C语言专用的头文件,里面只提供完成程序功能最基本的C语言类型指针和函数,所有的功能都通过此头文件对应的函数实现。

所有的定义放在extern "C" { }代码块中包裹起来。

看下面的示例:

假定有一个类定义 ,是用C++定义的。

apple.h

#ifndef __APPLE_H__
#define __APPLE_H__


enum class LogLevel {
    Trace  /// Most detailed output
    ,Debug
    ,Info
    ,Warn
    ,Error
    ,Fatal  /// Least detailed output
    ,Current  /// no-op, value indicates current level should be retained
};


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(0)
{
}
 
void Apple::SetColor(int color)
{
    m_nColor = color;
}
 
int Apple::GetColor(void)
{
    return m_nColor;
}

 此时如果直接用C++写main函数是这样的:

#include "apple.h"
#include <iostream>
 
// main for cpp
int main(void)
{
    Apple a;
    a.SetColor(1);
    printf("color = %d\n", a.GetColor());
    return 0;
}

编译生成mainpp程序

g++ -g -c apple.cpp   -o apple.o
g++ -g main.cpp -o mainpp  apple.o

但是如果将apple.cpp编译成一个库提供给C语言开发者,C语言肯定是无法调用 的。

所以就要有一个wrapper。

apple_c.h

#ifndef _APPLE_C_H_
#define _APPLE_C_H_


#if defined _WIN32 || defined WIN32  || defined _WINDOWS || defined __CYGWIN__
  #ifdef _DLL
    #ifdef __GNUC__
      #define DLL_PUBLIC __attribute__ ((dllexport))
    #else
      #define DLL_PUBLIC __declspec(dllexport)
    #endif
  #else
    #ifdef __GNUC__
      #define DLL_PUBLIC __attribute__ ((dllimport))
    #else
      #define DLL_PUBLIC __declspec(dllimport)
    #endif
  #endif
  #define DLL_LOCAL
#else
  #if __GNUC__ >= 4
    #define DLL_PUBLIC __attribute__ ((visibility ("default")))
    #define DLL_LOCAL  __attribute__ ((visibility ("hidden")))
  #else
    #define DLL_PUBLIC
    #define DLL_LOCAL
  #endif
#endif



#ifdef __cplusplus
extern "C" {
#endif


typedef enum  {
    LogLevelTrace = 0,  /// Most detailed output
    LogLevelDebug,
    LogLevelInfo,
    LogLevelWarn,
    LogLevelError,
    LogLevelFatal  /// Least detailed output
} AppLogLevel;

typedef void* ApplePtr; //指针类型定义
DLL_PUBLIC ApplePtr GetInstance(void);
DLL_PUBLIC void     ReleaseInstance(ApplePtr ptr);
DLL_PUBLIC void     SetColor(ApplePtr ptr, int color);
DLL_PUBLIC int      GetColor(ApplePtr ptr);

#ifdef __cplusplus
};
#endif

#endif

apple_c.cpp

#include "apple_c.h"
#include "apple.h"
#include <exception>
#include <iostream>



#ifdef __cplusplus
extern "C" {
#endif



DLL_PUBLIC ApplePtr GetInstance(void)
{
    return new Apple;
}

DLL_PUBLIC void ReleaseInstance(ApplePtr ptr)
{
 try {
        auto *client = static_cast<Apple*>(ptr);
        delete client;
        ptr = nullptr;
    } catch (std::exception &e) {
        std::cout<< e.what() << std::endl;
    }
}

DLL_PUBLIC void SetColor(ApplePtr ptr, int color)
{
    if (ptr == nullptr) {
        return ;
    }
    auto *pApple = static_cast<Apple*>(ptr);
    pApple->SetColor(color);
}
 
DLL_PUBLIC int GetColor(ApplePtr ptr)
{
    if (ptr == nullptr) {
        return -1;
    }
    auto *pApple = static_cast<Apple*>(ptr);
    return pApple->GetColor();
}




#ifdef __cplusplus
};
#endif

main.c的写法:

#include "apple_c.h"
#include <stdio.h>
 
int main(void)
{
    ApplePtr pApple;
    pApple = GetInstance();
    SetColor(pApple, 1);

    printf("color = %d\n", GetColor(pApple));
    ReleaseInstance(pApple);
    //printf("color = %d\n", GetColor(pApple));// pApple released
    return 0;
}

编译:

apple.cpp生成c++的静态库,再用apple_c.cpp生成一个wrapper的动态库libapple_c.so

再用main.c去调用这个动态库。

# compile .cpp
g++ -g -c apple.cpp   -o apple.o
g++ -g -c apple_c.cpp -o apple_c.o

# build cpp static library
ar rcs libapple.a  apple.o

# build c wraper libapple_c.so dynamic library
g++ -g -fpic -shared  -o libapple_c.so   apple_c.o  -L. -l apple -fvisibility=hidden


# build main.c 
gcc -g main.c -o mainc    -L. -l apple_c

结构体、类。已经在c++中定义过了,只需要定义对应的void *指针类型即可。

类的成员函数都要转换成普通的函数,一般将类对象指针作为第一个参数传入函数中。

enum类要在c头文件中重新定义

Exception处理。 c语言不支持Exception,所以异常需要在c++对应的wrapper cpp文件中进行处理。否则会在运行时出问题。

C语言封装的代码示例:

https://github.com/opentdf/client-cpp/blob/main/src/lib/include/tdf_client_c.h

https://github.com/opentdf/client-cpp/blob/main/src/lib/include/tdf_client.h

参考知识:

Standard C++ icon-default.png?t=N7T8https://isocpp.org/wiki/faq/mixing-c-and-cpp

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1246270.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

零代码AppLink平台触发事件组件

AppLink平台组件组成 AppLink平台组件分成三个板块触发事件组件、基础组件和数据连接器 触发组件下有三个组件&#xff0c;分别是Webhook、定时器、高级Webhook&#xff0c;那他们在AppLink平台里的原理、触发动作以及怎么使用呢&#xff1f;接下来为大家演示下。 Webhook是…

RabbitMQ 消息队列编程

安装与配置 安装 RabbitMQ 读者可以在 RabbitMQ 官方文档中找到完整的安装教程&#xff1a;Downloading and Installing RabbitMQ — RabbitMQ 本文使用 Docker 的方式部署。 RabbitMQ 社区镜像列表&#xff1a;https://hub.docker.com/_/rabbitmq 创建目录用于映射存储卷…

ssm+vue的企业文档管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。

演示视频&#xff1a; ssmvue的企业文档管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;ssm vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…

Mongodb6.0+,使用mongosh连接数据库

介绍: MongoDB的Shell工具mongosh是一个全功能的JavaScript和Node.js的14.x REPL与MongoDB的部署交互环境。 命令: 连接数据库:mongosh mongodb://127.0.0.1:27017 重置密码找到配置文件,将用户密码认证关闭: 连接数据库 找到admin库,然后看一下用户 删除用户重建, …

【数据结构/C++】线性表_顺序表的基本操作

#include <iostream> using namespace std; #define MaxSize 10 // 1. 顺序表 // 静态分配 typedef struct {int data[MaxSize];int length; // 当前长度 } SqList; // 静态分配初始化顺序表 void InitList(SqList &L) {for (int i 0; i < MaxSize; i){L.data[i]…

2023年项目管理工具排行榜:最佳项目管理工具推荐

如果你正在寻找一款项目管理软件&#xff0c;以下是你的最佳选择。让项目量化、可视化&#xff0c;资源合理分配、跟踪项目进度&#xff0c;帮助你的团队协作完成项目。 1、进度猫 进度猫是一款以甘特图为向导的轻量级在线免费项目进度管理工具。 基于甘特图、进度管理、任…

IP地址定位的误差问题及解析

随着互联网的普及&#xff0c;IP地址定位成为了数字时代中不可或缺的一部分&#xff0c;被广泛应用于各种场景&#xff0c;从位置服务到网络安全。然而&#xff0c;尽管IP地址定位提供了便利&#xff0c;但其准确性仍然受到多种因素的影响&#xff0c;存在一定的误差。本文将深…

conan 入门(三十二):package_info中配置禁用CMakeDeps生成使用项目自己生成的config.cmake

conanfile.py中定义的package_info()方法用于向package的调用者(conumer)提供包库名&#xff0c;编译/连接选项&#xff0c;文件夹等等信息&#xff0c;有了这些信息构建工具的generator就可以根据它们生成对应的文件&#xff0c;用于调用者引用package. 比如基于cmake的CMakeD…

zerotier 搭建 moon中转服务器 及 自建planet

搭建moon 服务器 环境准备 # 安装依赖 yum install wget gcc gcc-c git -y yum install json-devel -y# 下载及安装 curl -s https://install.zerotier.com/ | sudo bash节点ID 配置 配置moon.json文件 cd /var/lib/zerotier-one/# 导出依赖 zerotier-idtool initmoon ide…

【Git】git 更换远程仓库地址三种方法总结分享

因为公司更改了 gitlab 的网段地址&#xff0c;发现全部项目都需要重新更改远程仓库的地址了&#xff0c;所以做了个记录&#xff0c;说不定以后还会用到呢。 一、不删除远程仓库修改&#xff08;最方便&#xff09; # 查看远端地址 git remote -v # 查看远端仓库名 git rem…

gitlab各版本安装注意点:

研发团队在安装gitlab各版本过程中可能遇到各种问题&#xff0c;为了后续容易查看特将我们在实践过程中遇到的各类问题要点总结如下&#xff1a; gitlab 10.8.3 (564c342&#xff09;安装 centos Linux yum安装网址查找网址&#xff1a;gitlab/gitlab-ce - Results for gitla…

夜神模拟器 burp抓包 ADB 微信小程序

夜神模拟器 burp抓包 ADB 微信小程序 初始环境准备应用连接证书转换设置夜神模拟器环境ADB配置测试burp抓包 初始环境准备 既然想了解如何抓包&#xff0c;我想大多数是已经安装好 夜神模拟器 和 Burp 了&#xff0c;这里就不在赘述&#xff0c;直接开始操作。 openssl 的下载…

想象力即生产力,AIGC 未来的边界在哪里

随着 ChatGPT 在全球范围内爆红&#xff0c;有权威证券研报指出&#xff0c;AI 大模型的商业模式已成功跑通&#xff0c;并认为 AIGC 时代即将到来。 近年来&#xff0c;AI 大模型不断发展&#xff0c;算力成本也不断优化。训练和推理成本的不断下降&#xff0c;为 AIGC 的商业…

我是一名程序员,帮我规划一张学习人工智能原理的路线图,循序渐进,分阶段。

作为一名程序员&#xff0c;您已经具备了学习人工智能原理的良好基础。下面是一个循序渐进、分阶段的学习路线图&#xff1a; 初级阶段&#xff1a;基础知识 数学基础&#xff1a;学习线性代数、概率论、统计学和微积分。编程基础&#xff1a;熟练掌握Python编程&#xff0c;…

Java常量池理论篇:Class常量池、运行时常量池、String常量池、基本类型常量池,intern方法1.6、1.7的区别

文章目录 Class常量池运行时常量池String常量池基本类型常量池Integer 常量池Long 常量池 加餐部分 Class常量池 每个Class字节码文件中包含类常量池用来存放字面量以及符号引用等信息。 运行时常量池 java文件被编译成class文件之后&#xff0c;也就是会生成我上面所说的 …

nf_conntrack内核模块常见问题

nf_conntrack内核模块常见问题 问题描述排查步骤前置条件&#xff1a;启用nf_conntrack内核模块检查nf_conntrack配置 解决办法1:半数减少nf_conntrack buckets的值解决办法2:加倍调大m.min_free_kbytes值解决办法3:Linux社区权威答复-忽略告警 问题描述 内核报错 falling bac…

【C++初阶】四、类和对象(构造函数、析构函数、拷贝构造函数、赋值运算符重载函数)

相关代码gitee自取&#xff1a; C语言学习日记: 加油努力 (gitee.com) 接上期&#xff1a; 【C初阶】三、类和对象 &#xff08;面向过程、class类、类的访问限定符和封装、类的实例化、类对象模型、this指针&#xff09; -CSDN博客 引入&#xff1a;类的六个默认成员函数…

成为AI产品经理——模型评估指标

目录 一、模型评估分类 1.在线评估 2.离线评估 二、离线模型评估 1.特征评估 ① 特征自身稳定性 ② 特征来源稳定性 ③ 特征成本 2.模型评估 ① 统计性评估 覆盖度 最大值、最小值 分布形态 ② 模型性能指标 分类问题 回归问题 ③ 模型的稳定性 模型评估指标分…

学习视频剪辑方法:AI智剪助力,批量处理短视频无忧

随着短视频的兴起&#xff0c;越来越多的人开始关注如何有效地制作和发布这些内容。但是&#xff0c;短视频的制作并不容易&#xff0c;要耗费大量的时间和精力。现在有很多AI智能剪辑工具可以快速、高效地制作短视频。其中&#xff0c;AI智剪是一款非常受欢迎的视频剪辑功能&a…

NX二次开发UF_CURVE_ask_arc_data 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_ask_arc_data Defined in: uf_curve.h int UF_CURVE_ask_arc_data(tag_t arc, UF_CURVE_arc_p_t arc_coords ) overview 概述 Returns the data of an arc. The data is …