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"{
#endif
    void 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"{
#endif
    void 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(),替换成类的成员函数就可以了。

相关推荐

  1. C语言调用python

    2024-04-22 16:20:02       28 阅读
  2. c#程序调用c++开发dll

    2024-04-22 16:20:02       30 阅读
  3. 管道C语言(蓝桥杯题,暴力解决

    2024-04-22 16:20:02       60 阅读
  4. C语言标准

    2024-04-22 16:20:02       39 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-22 16:20:02       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-22 16:20:02       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-22 16:20:02       87 阅读
  4. Python语言-面向对象

    2024-04-22 16:20:02       96 阅读

热门阅读

  1. C++超级快读快写2.3

    2024-04-22 16:20:02       26 阅读
  2. php跨域和https访问http问题分析

    2024-04-22 16:20:02       33 阅读
  3. kafka

    2024-04-22 16:20:02       42 阅读
  4. 基于Python调用Gurobi求解器的入门文档

    2024-04-22 16:20:02       35 阅读
  5. 艾体宝观察 | 2024,如何开展网络安全风险分析

    2024-04-22 16:20:02       35 阅读
  6. 【无标题】

    2024-04-22 16:20:02       29 阅读
  7. PHP按自然月计算未来日期

    2024-04-22 16:20:02       30 阅读