Python使用ctypes调用c++函数的一些问题

Python使用Ctypes调用C++的一些问题

大家好!各位伙伴在接触Python代码时,在某些情况下,需要调用C++的一些函数。自己最近几天在弄这个问题,中间遇到了到了不少的问题,并且网上相关的内容比较少,因此分享这篇文章。本篇文章对很多底层原理没有过多解释,主要是为了去简单地使用,解决一些问题。中间一些内容可能不大准确,但是希望也能帮助大家,如果大家觉得有帮助的话,点个赞哦

本篇文章会分享Python代码如何调用c++,如何传递数值型参数字符串参数指针,以及最实用的Python传递list给c++中的数组

参考资源

自己查阅了很多博客,这方面的资料比较少,然后主要从B站的一个视频中得到了不少灵感,非常感谢那位老师,如果大家有时间可以去学习一下,会有很多收获。主要参考的资源如下:
Ctypes官方文档
B站一位大哥的视频

生成.so文件或.dll文件

在调用C++时,主要使用的是dll文件以及.so文件,很多博客有这方面的介绍,大家可以自行进行查阅。自己主要是使用.so文件来进行调用,在使用时应该差别不大。

一个简单的小示例

首先来看一个简单的示例,大致了解下基本流程,后面会介绍一些更加复杂的情况,比如传递简单的参数,如数字,字符串等,更复杂的还有Python 传递列表 给C++,以及如何从c++ 返回数组 给Python,自己暂时涉猎的深度就这些,如果有大家想要的东西,就接着往下看吧。

咱们来写个简单的HelloWorld程序,.py文件和.cpp文件在一个目录下:

Python使用ctypes调用c++函数的一些问题_第1张图片
C++程序的代码如下所示:

#include
#include
using namespace std;

extern "C"
void test1(){
    cout << "Hello world" << endl;
}

int main(){
    return 0;
}

这里要注意如果是c++的话,要想被Python调用的函数要加extern “C”,暂时记住即可,不知道原因暂时不影响。

然后生成.so文件,这里首先要安装一下g++,具体教程很多,大家可以自行搜索去进行解决,然后使用如下命令生成.so文件

g++ -fPIC -shared HelloWorld.cpp -o HelloWorld.so

执行完此命令后,可以发现多了一个.so文件
Python使用ctypes调用c++函数的一些问题_第2张图片
现在我们要开始编写我们的Python代码来调用我们写的c++函数了,Python代码如下:

import ctypes
dll = ctypes.cdll.LoadLibrary
lib = dll('./HelloWorld.so')
lib.test1()

前面相当于一个固定的写法,当然也有别的写法,在下才疏学浅,这一种能用就一直用的是这个啦,运行此文件,发现能正确输出:
Python使用ctypes调用c++函数的一些问题_第3张图片

传递简单的参数

当然,各位的需求远没有这么简单,有时我们需要传递一些参数,这里介绍一下自己了解的几种参数,包括整数,浮点数,字符串。此过程涉及Python,ctypes,c++之间的数据类型的转化,首先上一张官方文档的图:
Python使用ctypes调用c++函数的一些问题_第4张图片

整型参数

int类型可以直接传递,如下所示:

extern "C"
void testInt(int a){
    printf("调用了int测试函数\n");
    printf("接收的值为 %d", a);
}

执行如下代码

lib.testInt(1)
# lib.testInt(ctypes.c_int(1))  # 进行转换也可以正确输出

发现都可以正确进行输出
Python使用ctypes调用c++函数的一些问题_第5张图片

浮点型参数

再测试浮点型,浮点型数据需要进行转换

extern "C"
void testFloat(float a){
    printf("调用了flost测试函数\n");
    printf("接收的值为 %f", a);
}

若直接执行

lib.testFloat(66.6666)

发现会报错
Python使用ctypes调用c++函数的一些问题_第6张图片
此时进行转换,发现可以正确进行调用

lib.testFloat(ctypes.c_float(66.6666))

Python使用ctypes调用c++函数的一些问题_第7张图片

字符串型参数

若传递普通的字符,需要进行简单的转换,直接传递会出现问题

str = 'Give a thumb up!'
lib.testString(str, len(str))

在这里插入图片描述
此时进行简单的转化即可,在字符串前加个b,声明为字节对象即可。另外还有宽字符类型,进行相应的转化即可。

str = b'Give a thumb up!'
lib.testString(str, len(str))

发现能够正确输出
Python使用ctypes调用c++函数的一些问题_第8张图片

获取C函数返回值

前面分享了常见参数的传递,有时需要从c++函数返回的结果。默认返回的类型是int类型,若返回的是其他的类型,需要通过restype来进行指定

extern "C"
int testResInt(){
    return 1;
}

extern "C"
float testResFloat(){
    return 66.6666;
}

extern "C"
char * testResString(){
    return "Give a thumb up";
}

Python代码如下所示:

print(lib.testResInt())

lib.testResFloat.restype = ctypes.c_float
print(lib.testResFloat())

lib.testResString.restype = ctypes.c_char_p
print(lib.testResString())

发现能够正确输出:
Python使用ctypes调用c++函数的一些问题_第9张图片

指针的传递

若想Python传递指针给c++,此时通过argtypes可以指定传入的参数类型

extern "C"
int * testIntPointer(int * p){
    *p = 1;
    return p;
}

Python代码如下:

lib.testIntPointer.argtypes = (ctypes.POINTER(ctypes.c_int), )
lib.testIntPointer.restype = ctypes.POINTER(ctypes.c_int)

I = ctypes.c_int(100)
re = lib.testIntPointer(ctypes.byref(I))
print("返回值的类型", type(re))
print("返回值为", re.contents)

发现输出如下:
Python使用ctypes调用c++函数的一些问题_第10张图片

列表与数组的传递

Pyhton中什么数据类型使用地最多,没错,当然就是list了。那么现在就出现一个复杂的问题,也是当时自己最需要解决的一个问题,就是如何将列表类型的数据传递给c++函数。c++中跟list数据类型相似的就是数组了,因此现在的问题就是如何将列表传递给c++的数组。

extern "C"
void testArray(int *arr, int size){
    printf("调用了testArray函数\n");
    for(int i = 0; i < size; ++i)
        cout << arr[i] << " ";
}
a = [i for i in range(10)]  # 生成一个列表
TenArrType = ctypes.c_int * len(a)
ca = TenArrType(*a)
lib.testArray.argtypes = (TenArrType, )
lib.testArray(ca, len(a))

所以传递list的步骤为,首先c++代码正常编写即可,在Python代码中,首先要声明个类型 (list中数据对应的ctypes的类型) * (list的长度),例如示例中的 ctypes.c_int * len(a),然后再利用 (类型)(*列表) 构造一个新的对象,个人感觉可以理解成就是将list中的数据拷贝到了这块新的空间。最后再指定一下传入的参数类型,后面就可以直接调用了

运行结果如下所示
Python使用ctypes调用c++函数的一些问题_第11张图片

如何从c++返回数组给python

这块涉及的问题比较复杂,如果要真正实现此功能,好像还挺麻烦的,我暂时还没学会。在此我分享一个简单粗暴的方法,能解决我们的需求。就是上面我们已经学习了如何去传递列表给c++,在c++中这是数组的形式,c++代码中在这块内存可以进行访问并写入,因此我们只需要在Python中事先定义好这样的变量,在c++中直接将值写入其中就行,这样便有异曲同工之妙。

extern "C"
void testArray2(int *arr, int * arr2, int size){
    for(int i = 0; i < size; ++i)
        arr2[i] = arr[i] * 4;
}
a = [i for i in range(10)]  # 生成一个列表
b = [0] * len(a)
TenArrType = ctypes.c_int * len(a)
ca = TenArrType(*a)
cb = TenArrType(*b)
lib.testArray2.argtypes = (TenArrType, TenArrType, )
lib.testArray2(ca, cb, len(a))
for i in range(len(b)):
    print(cb[i], end=' ')

发现输出如下
Python使用ctypes调用c++函数的一些问题_第12张图片
到此,这次的分享就结束了,自己弄的也不深入,只是为了解决这个问题,有些地方不对望指正,如果觉得有帮助点个赞哦

你可能感兴趣的:(python,c++)