文章目录
本文以windows环境下的.dll动态链接库为背景展开,有关linux下的.so动态链接库的相关用法会在另外一篇文章中展开讲解。
1. 背景知识
一直以来python都被称为胶水语言,能够轻易地操作其他程序,轻易地包装使用其他语言编写的库。下面简单介绍下如何使用python
来调用C/C++
编写的动态库。首先了解下动态链接库及C/C++
动态库的区别。
1.1 动态链接库
使用VS2017创建动态链接库DllDemo,代码如下:
//整型相加
__declspec(dllexport) int addInt(int a, int b)
{
return a + b;
}
//浮点型相加
__declspec(dllexport) float addFloat(float a, float b)
{
return a + b;
}
//传递float指针类型参数
__declspec(dllexport) void changeFloat(float *a)
{
*a = 100.00;
}
//传递char指针类型参数,返回指针类型参数
__declspec(dllexport) char* pointCh(char *a)
{
return a;
}
使用dumpbin.exe工具,在cmd命令行使用
dumpbin.exe -exports DllDemo.dll
查看动态库的导出函数如下:
从上图可以看出动态库导出了4个函数,与上面代码中的导出函数一致。但是函数名长得很奇怪,这是因为在编译链接时,C++
会按照自己的规则篡改函数的名称,这一过程称为"名字改编",C++
支持函数重载,就是在函数名字改编阶段记录下函数的相关参数信息。
C++
标准并没有定义名字改编的标准,因此会导致不同编译器编译出来的动态库不能通用。
1.2 extern "C"
作用
相比之下,C标准规定了名字改编的标准,extern "C"
指示编译器在编译代码是按照C的标准进行编译。
在上述代码的每个函数名前都加上extern "C"
关键字。
extern "C" __declspec(dllexport) int addInt(int a, int b)
{
return a + b;
}
extern "C" __declspec(dllexport) float addFloat(float a, float b)
{
return a + b;
}
extern "C" __declspec(dllexport) void changeFloat(float *a)
{
*a = 100.00;
}
extern "C" __declspec(dllexport) char* pointCh(char *a)
{
return a;
}
查看动态库的导出函数,可以看到导出的函数名和函数的定义是一致的。
如果extern "C"
修饰的函数进行了重载,则会在编译时报错,因为C语言并不支持函数的重载。
1.3 动态链接库加载方式
1.3.1 隐式链接
隐式链接需要
.dll .lib
文件
#include <iostream>
#include <Windows.h>
using namespace std;
//隐式加载需要导入动态库的导入库
#pragma comment(lib, "../Debug/DllDemo.lib")
//dll中导出的函数通过直接声明或者包含头文件的方式
extern "C" _declspec(dllimport) int addInt(int a, int b);
extern "C" _declspec(dllimport) float addFloat(float a, float b);
int main()
{
//调用动态库中的函数
cout << addInt(1, 2) << endl;
cout << addFloat(1.25, 2.25) << endl;
}
通过vs自带的工具lib,通过命令
lib /list XXXX.lib
,可以查看一个.lib文件是静态库还是导入库
1.3.2 显式链接
显式链接需要.dll, 需要事先知道导出函数的签名,不需要.lib和.h文件