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代码中加载.so并调用对应的方法,调用过程是通过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;
}
发布了71 篇原创文章 · 获赞 53 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/BigBoySunshine/article/details/89566012