python调用c/c++代码以及解决ctypes.ArgumentError: argument 1: class 'TypeError': Don't know how to convert
python在人工智能大潮的推动下越来越火,但python作为高级语言,在运行效率的上存在着短板。但是python可以访问c/c++代码,这样就可以把耗时的运算操作用c/c++实现,然后用python来调用。
整体过程是通过gcc把c/c++代码编译成.so库,然后在python代码中加载并调用对应的方法,调用过程是通过ctypes来完成。
一,安装gcc
首先需要安装gcc,已安装的童鞋跳过该步骤。
1,在https://sourceforge.net/projects/mingw/files/,页面下载Download mingw-get-setup.exe。
2,安装,比如安装在C:\MinGw目录下。安装完成后关闭MinGw installation manager窗口。
3,修改环境变量,在path中加入c:\MinGw\bin。
4,在cmd中输入命令mingw-get install gcc,稍等片刻gcc就安装完成了。
二,代码实现过程
1,C语言代码:calc.c
#include <stdio.h>
#include <stdlib.h>
int sum(int a, int b)
{
printf("you input %d and %d\n", a, b);
return a+b;
}
2,通过gcc编译生成动态库libcalc.so,在calc.c的目录下:
gcc -o libcalc.so -shared -fPIC calc.c
在该目录下会生成libcalc.so文件。
3,python调用.so库,创建pycalc.py
import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll("./libcalc.so")
result=lib.sum(2, 4)
print(result)
执行:python pycalc.py
如果提示:不是32位应用程序的报错,是因为你的python是64位的,这里需要32位的,换成32位的python就可以了。其他方案具体没有深究。。。
运行成功的话会有如下输出:
4,此时感觉已经万事大吉,可以征服全世界了。。。
巴特,ctypes模块在连接python和c/c++时数据类型存在一个映射关系。
如果我们传入的参数是float,返回的类型也是float
#include <stdio.h>
#include <stdlib.h>
float sum(float a, float b)
{
printf("you input %f and %f\n", a, b);
return a+b;
}
此时编成.so,修改代码:
import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll("./libcalc.so")
result = lib.sum(2.0, 4.0)
print(result)
再运行代码就出问题了,
这是因为ctypes模块在连接python和c/c++时数据类型存在一个映射关系,如下
如果修改代码,把入参类型改成映射的类型,如:
import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll("./libcalc.so")
result = lib.sum(ctypes.c_float(2.0), ctypes.c_float(4.0))
print(result)
此时c/c++就可以拿到正确的参数了。
但是结果呢?结果是32,WTF!!!
把result的类型打印出来
可以看到是int类型,也就是虽然我们c/c++代码的函数返回的类型是float,但python接收到的类型却是int。
解决:
在调用c方法前可以指定传入参数的类型和返回参数的类型。
lib.sum.argtypes = [ctypes.c_float, ctypes.c_float]
lib.sum.restype = ctypes.c_float
此时就可以得到正常结果了
完成代码
pycalc.py
import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll("./libcalc.so")
# 设置sum()函数传入参数的类型
lib.sum.argtypes = [ctypes.c_float, ctypes.c_float]
# 这是sum()函数返回参数的类型
lib.sum.restype = ctypes.c_float
result = lib.sum(ctypes.c_float(2.0), ctypes.c_float(4.0))
print("result:"+str(result)+" type:"+str(type(result)))
calc.c
/***gcc -o libcalc.so -shared -fPIC calc.c*/
#include <stdio.h>
#include <stdlib.h>
float sum(float a, float b)
{
printf("you input %f and %f\n", a, b);
return a+b;
}