c hello world_C和C++使用对方编译的动态链接库

C使用C++编译出来的动态链接库,C++使用C编译出来的动态链接库,C使用C编译出来的动态链接库,C++使用C++编译出来的动态链接库……

最近和师兄们搭伴做加密系统,自己负责加密算法部分,师兄们负责更加底层的硬件接口部分。但是因为个人原因我不大喜欢 C 语言,当然是相比较于 C++ 而言,所以自己就用了 C++ 去实现加密算法。这么一来,就涉及到和师兄写的程序之间接口问题,于是乎就研究了下怎样导出动态链接库以供他人使用。

对于 CC++ 之间的关系,可不是 JavaJavaScript 之间的关系,所以操作起来相对而言还是比较容易的,但是也有一些坑需要注意,要不然也不至于在2020年的国庆节折腾这折腾了两天 ,难度系数表如下表:

0b73a67d89029e9ba445ca383b03dc69.png

因为 C/C++ 对系统环境比较敏感,这里列出写这篇文章时的系统情况:

f19b11dede5a57abbd5ebf930c089711.png

噢,对了,还有重要的 CC++ 版本:

  • C :C99
  • C++ :C++17

1. C导出动态链接库给C++用

什么?上来为什么要说这个?那肯定是因为简单啊!那为什么不说另外两个更简单的?那肯定是因为没做啊

先来考虑这样一个需求:小张小明是朋友,小张喜欢 C++ ,小明不得不用 C ,而小明需要给小张提供一些库,小张使用小明提供的库进行上层开发,那么也就是:

  • 小明使用 C 语言写了个驱动,导出 DLL 动态链接库
  • 小张拿到小明导出的 DLL 动态链接库,引入到项目中,使用在 DLL 中编译好的函数(或数据结构)

那么他俩可以这样做:

1.1 小明的工作目录

小明的工作目录长这样:

D:.
│  CMakeLists.txt
│  library.c
│  library.h
└─cmake-build-debug

其中的 cmake-build-debug 是用来存放 CMake 执行过程中产生的文件,可以暂时忽略不计,主要关注这几个文件的内容:

  1. CMakeLists.txt 规定了怎样去编译这个库,怎样导出。这里主要说明了项目名称,使用的语言,C 语言的标准用哪一版,以及库的依赖文件和导出方式(SHARED )
cmake_minimum_required(VERSION 3.17)
project(C_Lib C)
set(CMAKE_C_STANDARD 99)
add_library(C_Lib SHARED library.c library.h)
  1. library.h 函数的声明,简简单单,普普通通
#ifndef C_LIB_LIBRARY_H
#define C_LIB_LIBRARY_H
void hello(void);
#endif //C_LIB_LIBRARY_H
  1. library.c 函数的实现,更加朴素
#include "library.h"
#include <stdio.h>
void hello(void) {
    printf("Hello, World!n");
}

完成这些之后,点击编译项目或 Ctrl+F9 快捷键编译或者输入命令编译:

cmake.exe --build .cmake-build-debug --target C_Lib -- -j 6

完成后可以看到如下输入:

[100%] Built target C_Lib

那么可以在 cmake-build-debug 目录下找到 libC_Lib.dll 文件,这个文件就是用来给小张用的。

好了,小明可以去吃苹果了 。

1.2 小张的工作目录

小张的工作目录长这样:

D:SOURCEC++TEMPCXX_EXE
│  CMakeLists.txt
│  libC_Lib.dll
│  main.cpp
└─cmake-build-debug 

这里主要多了一个 libC_Lib.dll 文件,这个文件就是来自小明的,那么该如何使用里面定义的 hello() 方法?

  • 首先,需要导入到当前项目中,这里使用 CMakeLists.txt 来完成:
cmake_minimum_required(VERSION 3.17)
project(CXX_Exe)
set(CMAKE_CXX_STANDARD 17)
link_directories(.) # 从当前目录中寻找链接文件
add_executable(CXX_Exe main.cpp library.h)
target_link_libraries(CXX_Exe libC_Lib.dll) # 将 libC_Lib.dll 链接到 CXX_Exe 目标文件中
  • 使用头文件 library.h 中引入函数声明
#ifndef C_LIB_LIBRARY_H
#define C_LIB_LIBRARY_H
#ifdef __cplusplus
extern "C" {
#endif
void hello();
#ifdef __cplusplus
}
#endif
#endif //C_LIB_LIBRARY_H
  • C++ 源文件 main.cpp 中使用 hello() 函数
#include "library.h"
int main() {
    hello(); // >: Hello, World!
    return 0;
}

不过!重点之一来了!为什么在头文件 library.h 中写一个 extern "C" 呢?是因为 C 的编译链接过程,中间代码不会修改函数名称,而 C++ 在这个过程中将会修改!因此,为了让 C++ 识别出来 C 函数,需要使用 extern "C" 来指明,这个函数是 C 过来的。

否则会异常退出:undefined reference to 'hello()' collect2.exe: error: ld returned 1 exit status

**重点之二,**在 CLion 中,仅仅在 CMakeLists.txt 中声明怎样链接,怎样找动态链接库是不够的,还需要在 Run Configurations 设置中去添加环境变量 PATH={DLL文件所在的目录} 才可以,要不然就直接放到 CLion 已知的环境目录下。

否则会异常退出: Process finished with exit code -1073741515 (0xC0000135)

至此,小张小明合作愉快,任务完成 。

2. C++导出动态链接库给C用

还是小张和小明,还是 CC++ ,只不过这次换成了小张提供动态链接库给小明使用。

2.1 小张的工作目录

小张需要提供动态链接库,他的工作目录长这样:

D:.
│  CMakeLists.txt
│  library.cpp
│  library.h
└─cmake-build-debug

还是跟之前一样, cmake-build-debug 里面找动态链接文件,而 CMakeLists.txt 里面规定了怎样去编译这个程序。

挨着牌的来康康每个文件写了啥:

  • CMakeLists.txt
cmake_minimum_required(VERSION 3.17)
project(CXX_Lib)
set(CMAKE_CXX_STANDARD 17) # 设置 C++ 标准为 17
add_library(CXX_Lib SHARED library.cpp library.h) # 规定了依赖哪些文件去产生动态链接文件,以及动态链接文件类型
  • library.h
#ifndef CXX_LIB_LIBRARY_H
#define CXX_LIB_LIBRARY_H
extern "C"
// 声明下面这个函数,是要按照 C 语言的标准去导出的,不要改名啦~
void hello();
#endif //CXX_LIB_LIBRARY_H

这里的不同在于,直接在动态链接库的头文件中声明了 extern "C" 而不是在用到动态链接文件的地方。

  • library.cpp
#include "library.h"
#include <iostream>
void hello() {
    std::cout << "Hello, World!" << std::endl;
}

经历和小明一样的编译过程:

cmake.exe --build .cmake-build-debug --target CXX_Lib -- -j 6

然后在 cmake-build-debug 目录下找到 libCXX_Lib.dll 文件,然后丢给小明,然后小张去喝牛奶 了。

2.2 小明的工作目录

小明拿到小张的动态链接文件后,直接放到工作目录下,然后他的工作目录就长这样了:

D:.
|   CMakeLists.txt
|   libCXX_Lib.dll
|   library.h
|   main.c
---cmake-build-debug

其中的 libCXX_Lib.dll 就是小张那取过来的。

  • 一样的流程,首先使用 CMakeLists.txt 导入到项目中
cmake_minimum_required(VERSION 3.17)
project(C_Exe C)
set(CMAKE_C_STANDARD 99)
link_directories(.) # 从哪里找链接文件
add_executable(C_Exe main.c library.h)
target_link_libraries(C_Exe libCXX_Lib.dll) # 使用这个动态链接库
  • 然后声明头文件 library.h
#ifndef CXX_LIB_LIBRARY_H
#define CXX_LIB_LIBRARY_H
void hello();
#endif //CXX_LIB_LIBRARY_H
  • 最后使用 main.c
#include <stdio.h>
#include "library.h"
int main() {
    hello(); // >: Hello, World!
    return 0;
}

虽然小明这里没有了 extern "C" 的注意事项,但是仍然需要在 CLionRun Configurations 里面配置 PATH={DLL文件所在的目录} 才能使用,否则还是报 Process finished with exit code -1073741515 (0xC0000135)

好了,小明终于可以去休息了,我也去休息一下 ~~~


写完后突然想起来,我和师兄为啥不统一一下语言呢? 省时省力还省得这两天折腾来折腾去。

不过想想,有了这个经验,以后可以专门给 JavaPython 等程序写动态链接库,也未尝不是件好事。

真是让人恍然大明白!

公众号:Algorithms
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值