C语言工程调用C++库解决方案

ops/2024/9/20 7:18:34/ 标签: c语言, c++, 开发语言

本文为C语言工程调用C++库的解决方案。

应用场景: 需要C++程序编译成的库提供函数接口,来解决C语言工程的需求。

人的出场顺序真的很重要,很多人如果换一个时间认识,换一个时间共处,一切都将是不一样的场景,不一样的结局。所以,人生有无限种可能,我的人生,是现在这一种。感谢大家恰到好处的出现,组成我最好的一种可能。

------ 大家好啊 我是 暮冬Z羡慕

一、C++库可以编辑的情况

C++库由自己编写,可以决定头文件书写的位置

// hello.cpp
#include "hello.h"
#include "iostream" //将用到的C++标准库,如iostream,放在本cpp文件中
using namespace std;
void sayHello(){cout<< " # iostream: i am saying hello !" << endl;printf(" # c: i am saying hello !\n");
}

创建 hello.cpp 文件,实现 sayHello() 功能,分别用C++标准库和C标准库的输入输出功能打印 hello!

①需要注意的是 “ 将C++标准库放在该cpp文件中”,原因后续指出。

// hello.h
#include "stdio.h"  // 这里不能出现C++标准库
void sayHello();

创建头文件 hello.h 这里可以添加C语言标准库,但是不要把C++标准库放在这里。

以上 hello.h 和 hello.cpp 模拟了C++库。为了使C语言工程能够调用该库,需要增加一个中间层:

// helloWapper.cpp
#include "helloWapper.h"
void Wapper_sayHello(){sayHello();
}

创建中间层 helloWapper.cpp , 对想要使用的C++库函数进行封装,即: 通过 Wapper_sayHello() 调用 sayHello()

// helloWapper.h
#include "hello.h"
#ifdef __cplusplus
extern "C"{
#endifvoid Wapper_sayHello();
#ifdef __cplusplus
}
#endif

 创建中间层头文件 helloWapper.h,暴露 Wapper_sayHello() 接口。中间出现的 extern "C" {} 是告诉G++编译器,对中间的函数按照C语言的方式进行编译。

然后将上述两个CPP文件编译成 静态库 ,使用的 CMakeLists.txt 文件如下:

cmake_minimum_required (VERSION 3.5)
project (demo)
include_directories (${PROJECT_SOURCE_DIR}/include ) # 指定头文件位置
set (test_call_LIST ${PROJECT_SOURCE_DIR}/src/hello.cpp${PROJECT_SOURCE_DIR}/src/helloWapper.cpp)  # 指定需要编译的CPP文件
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) # 指定库输出路径
add_library(hello STATIC ${test_call_LIST}) # 编译

所有文件结构如下:

在工程根目录输入:

mkdir build & cd build

cmake ..

make

bin文件夹下就会出现 封装好的库 libhello.a

创建mian.c来模拟C语言工程:

#include "stdio.h"
#include "helloWapper.h"  // 调用C++库接口
int main(){Wapper_sayHello();return 0;
}

A:通过命令行进行编译运行

回到工程根目录,编译main.c , 运行:

cd ..
gcc -o Hello ./src/main.c -I./include -L./bin -lhello -lstdc++
./Hello

B:通过 Cmake 编译运行

在工程根目录,将CMakeList.txt内容替换为

# CMakeList.txt
cmake_minimum_required (VERSION 3.5)
project (demo)
include_directories (${PROJECT_SOURCE_DIR}/include)  # 指定头文件目录
find_library(Hello_LIB hello HINTS ${PROJECT_SOURCE_DIR}/bin) # 引入libhello.a静态库
set (hello_List ${PROJECT_SOURCE_DIR}/src/main.c)
add_executable (Hello ${hello_List})  # 默认gcc 编译 main.c
target_link_libraries (Hello ${Hello_LIB} stdc++)

命令行运行:

cd build
cmake ..
make
./Hello

A B 两种方式均输出结果: 至此C语言工程能够成功调用C++库

以上A B两种方式中均出现 stdc++ ,一般以libstdc++.so的方式存在,是C++标准库。

可以看下图 “G++ and GCC”

“G++ and GCC”

GCC在编译时不会自动链接 C++ 标准库, 因此hello.cpp用到的 类似 "iostream"等C++标准库需要手动链接,否则会出现以下错误:

二、C++库为第三方库,无法编辑的情况

在《一、C++库可以编辑的情况》 中提到 【①需要注意的是 “ 将C++标准库放在该cpp文件中”】 是因为 GCC编译不仅找不到C++标准库 stdc++ ,也找不到C++标准库的头文件。如果在hello.h中引用“iostream", 那么用GCC编译C语言工程时,会报找不到头文件错误。

// hello.h
#include "stdio.h"  
#include "iostream"  // 这里出现了C++标准库
void sayHello();

但是当我们想用的C++库为第三方库,而它在头文件里引用了大量C++标准库的情况下,该如何处理呢?

再看图 “G++ and GCC”,里面指明G++编译器能够编译C和C++文件,且能够自动链接C++标准库。所以在这种情况下,只需要在编译C语言工程的时候,指定G++为编译器(编译C文件默认使用的是GCC编译器)就可以了。

下面是与《一、C++库可以编辑的情况》相似的总体流程(有修改的地方会有注释):

// hello.cpp
#include "hello.h"  // C++ 标准库头文件转移到 hello.h 中
using namespace std;
void sayHello(){cout<< " # iostream: i am saying hello !" << endl;printf(" # c: i am saying hello !\n");
}

创建 hello.cpp 文件,实现 sayHello() 功能,分别用C++标准库和C标准库的输入输出功能打印 hello!

// hello.h
#include "stdio.h" 
#include "iostream"  // C++ 标准库出现在这里
void sayHello();

 创建头文件 hello.h

以上 hello.h 和 hello.cpp 模拟了C++库。为了使C语言工程能够调用该库,需要增加一个中间层:

// helloWapper.cpp
#include "helloWapper.h"
void Wapper_sayHello(){sayHello();
}

 创建中间层 helloWapper.cpp , 对想要使用的C++库函数进行封装,即: 通过 Wapper_sayHello() 调用 sayHello()

// helloWapper.h
#include "hello.h"
#ifdef __cplusplus
extern "C"{
#endifvoid Wapper_sayHello();
#ifdef __cplusplus
}
#endif

创建中间层头文件 helloWapper.h,暴露 Wapper_sayHello() 接口。中间出现的 extern "C" {} 是告诉G++编译器,对中间的函数按照C语言的方式进行编译。

然后将上述两个CPP文件编译成 静态库 ,使用的 CMakeLists.txt 文件如下:        

cmake_minimum_required (VERSION 3.5)
project (demo)
include_directories (${PROJECT_SOURCE_DIR}/include ) # 指定头文件位置
set (test_call_LIST ${PROJECT_SOURCE_DIR}/src/hello.cpp${PROJECT_SOURCE_DIR}/src/helloWapper.cpp)  # 指定需要编译的CPP文件
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) # 指定库输出路径
add_library(hello STATIC ${test_call_LIST}) # 编译

所有文件结构如下:

在工程根目录输入:

mkdir build & cd build
cmake .. 
make 

bin文件夹下就会出现 封装好的库 libhello.a

创建mian.c来模拟C语言工程:

#include "stdio.h"
#include "helloWapper.h"  // 调用C++库接口
int main(){Wapper_sayHello();return 0;
}

A:通过命令行进行编译运行

回到工程根目录,编译main.c , 运行:

编译器使用了 g++ ,可以自动搜索C++标准库路径及链接C++标准库,因此不需要再加 “ -lstdc++”。

cd ..
g++ -o Hello ./src/main.c -I./include -L./bin -lhello
./Hello

B:通过 Cmake 编译运行

在工程根目录,将CMakeList.txt内容替换为:

# CMakeList.txt
cmake_minimum_required (VERSION 3.5)
project (demo)
SET(CMAKE_C_COMPILER "g++")  # 指定使用  g++ 编译器进行编译
include_directories (${PROJECT_SOURCE_DIR}/include)  # 指定头文件目录
find_library(Hello_LIB hello HINTS ${PROJECT_SOURCE_DIR}/bin) # 引入libhello.a静态库
set (hello_List ${PROJECT_SOURCE_DIR}/src/main.c)
add_executable (Hello ${hello_List})
target_link_libraries (Hello ${Hello_LIB} stdc++)

编译、执行:

cd build
cmake ..
make
./Hello

至此,C语言工程调用C++库解决方案结束。

可能会有人问,C++库都是类,如何暴露接口?

很简单,将上文中出现的helloWapper.cpp中的函数里面的 sayHello(),替换成类的成员函数就可以了。


http://www.ppmy.cn/ops/15109.html

相关文章

鸿蒙原生应用元服务-访问控制(权限)开发应用权限列表二

ohos.permission.ACCELEROMETER 允许应用读取加速度传感器的数据。 权限级别 &#xff1a;normal 授权方式 &#xff1a;system_grant ACL使能 &#xff1a;TRUE ohos.permission.GYROSCOPE 允许应用读取陀螺仪传感器的数据。 权限级别 &#xff1a;normal 授权方式 &a…

C++高级特性:异常概念与处理机制(十四)

1、异常的基本概念 异常&#xff1a;是指在程序运行的过程中发生的一些异常事件&#xff08;如&#xff1a;除数为0&#xff0c;数组下标越界&#xff0c;栈溢出&#xff0c;访问非法内存等&#xff09; C的异常机制相比C语言的异常处理&#xff1a; 函数的返回值可以忽略&…

Mongodb支持事务吗?

一、概念 1.1、MongoDB事务简介 MongoDB 是一个非关系型数据库管理系统&#xff0c;最初并不支持事务。然而&#xff0c;随着时间的推移&#xff0c;MongoDB 在其4.0版本中引入了多文档事务支持&#xff0c;使得在单个集合中执行多个操作成为可能。 In MongoDB, an operation…

C#面:阐述什么是泛型,泛型的优点有哪些?

泛型是 C# 中的一种特性&#xff0c;它允许我们编写可以在不同类型上工作的可重用代码。 通过使用泛型&#xff0c;我们可以编写更加灵活和通用的代码&#xff0c;而不需要为每种类型都编写重复的代码。 泛型的优点有以下几个方面&#xff1a; 代码重用&#xff1a;使用泛型可…

装饰器模式

一、实现原理 装饰器设计模式&#xff08;Decorator&#xff09;是一种结构型设计模式&#xff0c;它允许动态地为对象添加新的行为。它通过创建一个包装器来实现&#xff0c;即将对象放入一个装饰器类中&#xff0c;再将装饰器类放入另一个装饰器类中&#xff0c;以此类推&am…

nginx反向代理

简介 Nginx反向代理是一种服务器架构模式&#xff0c;它允许Nginx服务器接收客户端的请求&#xff0c;然后将这些请求转发到上游服务器&#xff08;例如应用服务器&#xff09;进行处理&#xff0c;并将处理后的响应返回给客户端。在这个过程中&#xff0c;Nginx充当了客户端和…

如何提交已暂存的更改到本地仓库?

文章目录 如何提交已暂存的更改到本地Git仓库&#xff1f;步骤1&#xff1a;确认并暂存更改步骤2&#xff1a;提交暂存的更改到本地仓库 如何提交已暂存的更改到本地Git仓库&#xff1f; 在Git版本控制系统中&#xff0c;当你对项目文件进行修改后&#xff0c;首先需要将这些更…

前端开发攻略---用原生JS在网页中也能实现 文本转语音!

1、原理 语音合成 (也被称作是文本转为语音&#xff0c;英语简写是 tts) 包括接收 app 中需要语音合成的文本&#xff0c;再在设备麦克风播放出来这两个过程。 Web API中对此有一个主要控制接口 SpeechSynthesis&#xff0c;外加一些处理如何表示要被合成的文本 (也被称为 utte…

(避雷指引:管理页面超时问题)windows下载安装RabbitMQ

一、背景&#xff1a; 学习RabbitMQ过程中&#xff0c;由于个人电脑性能问题&#xff0c;直接装在windows去使用RabbitMQ&#xff0c;根据各大网友教程&#xff0c;去下载安装完之后&#xff0c;使用web端进行简单的入门操作时&#xff0c;总是一直提示超时&#xff0c;要么容…

2024年华为OD机试真题-考勤信息-Python-OD统一考试(C卷D卷)

题目描述: 公司用一个字符串来表示员工的出勤信息: absent:缺勤 late:迟到 leaveearly:早退 present:正常上班 现需根据员工出勤信息,判断本次是否能获得出勤奖,能获得出勤奖的条件如下: 缺勤不超过一次;没有连续的迟到/早退;任意连续7次考勤,缺勤/迟到/早退不超过…

GaussDB轻量化运维管理工具介绍

前言 本期课程将从管理平台的架构出发&#xff0c;结合平台的实例管理、实例升级、容灾管理和监控告警的功能和操作介绍&#xff0c;全面覆盖日常运维操作&#xff0c;带您理解并熟练运用GaussDB运维平台完成运维工作。 一、GaussDB 运维管理平台简介 开放生态层 友好Web界面…

Python 基于docker部署的Mysql备份查询脚本

前言 此环境是基于docker部署的mysql&#xff0c;docker部署mysql可以参考如下链接&#xff1a; docker 部署服务案例-CSDN博客 颜色块文件 rootbogon:~ 2024-04-18 16:34:23# cat DefaultColor.py ######################################################################…

Python爬虫入门指南--爬虫技术的由来、发展与未来--实战课程大赠送

爬虫&#xff0c;也称为网络爬虫或网络蜘蛛&#xff0c;是一种自动化程序&#xff0c;专门用于遍历互联网并收集数据。这种技术的起源、发展和未来都与互联网紧密相连&#xff0c;并在信息检索、数据挖掘等多个领域发挥着不可或缺的作用。 "免费IP池大放送&#xff01;助…

我的读书摘记《点燃孩子的学习动力:关于儿童学习兴趣的真相》

德韦克认为乔丹的经历揭示了那些最卓越的学习者身上的一个秘密&#xff1a;人的天赋&#xff0c;是可以不断发展的&#xff01;不管早期的天赋如何&#xff0c;人终将不断超越自己&#xff0c;发展自己的天赋。 思维方式决定了学习的成功与否&#xff01;这也意味着&#xff0…

【CCF推荐-C类】计算机学术会议截稿信息2条

中国计算机学会推荐国际学术会议和期刊目录自2010年8月首次发布以来&#xff0c;已历经五版&#xff0c;得到了计算机领域科研工作者的广泛关注。 目录共包含十个领域&#xff0c;分为ABC三类&#xff1a;A类是国际上极少数顶会与顶刊&#xff1b;B类代表领域内高水平的会议与…

前端兼容 适配

一、浏览器 1、内核 浏览器内核优缺点IEtrident不安全Chromewebkit -> blink速度快&#xff0c;有兼容safriwebkit有兼容firefoxgecko功能强大 耗性能Operapresto -> blinkpresto 速度快&#xff0c;有兼容 2、浏览器兼容 1、html兼容 超链接访问过后hover样式不再出…

Redis中set数据类型详解

SADD key member [member …] summary: Add one or more members to a set since: 1.0.0 SCARD key summary: Get the number of members in a set since: 1.0.0 SDIFF key [key …] summary: Subtract multiple sets since: 1.0.0 SDIFFSTORE destination key [key …] sum…

mybatis的SqlSession

先来看一下sqlsession接口&#xff0c;发现它为我们定义了很多对数据库数据操作的相关方法。 public interface SqlSession extends Closeable {<T> T selectOne(String var1);<T> T selectOne(String var1, Object var2);<E> List<E> selectList(Str…

使用gogs搭建git服务器-注意事项

背景 自己的服务器上一直是用gitlab部署作为git服务,但是gitlab对机器的内存要求有点高,4G内存的小服务器开了gitlab就剩下几百兆内存了,别的服务器就受限制了,于是决定更换一个。 其实我对仓库管理系统要求没有太高,正常的上传下载浏览就行了。最后决定使用gogs。 踩坑 我…

Linux网络设置

将Linux主机接入到网络&#xff0c;需要配置网络相关设置 一般包括&#xff1a;主机名&#xff1b;IP/netmask&#xff1b;路由&#xff1a;默认网关&#xff1b;DNS服务器&#xff1a;主DNS服务器&#xff0c;次DNS服务器&#xff0c;第三个DNS服务器 网卡的配置文件在&…