结构体传参:http://www.jb51.net/article/52513.htm
准备工作:
C++文件(cpp):(注意在函数声明上加上extern "C" 的修饰)
#include <stdio.h> extern "C" { __declspec(dllexport) int Double(int x); __declspec(dllexport) float floatAdd(float a,float b); __declspec(dllexport) void HelloWorld(char * str); __declspec(dllexport) void Ints(int * arr,int n); } int Double(int x){ return x*2; } float floatAdd(float a,float b) { return a+b; } void HelloWorld(char * str){ puts(str); } void Ints(int * arr,int n){ for(int i=0;i<n;i++){ printf("%d ",arr[i]); } puts(""); }
用g++(mingw64位)编译为dll:
g++ dlltest.cpp -shared -o dlltest.dll -Wl,--out-implib,dlltest.lib pause
在python脚本中加载dll :
from ctypes import * dll = cdll.LoadLibrary('DLL/dlltest.dll')
1.如果不加任何修饰,默认传入参数为int,传出参数也为int
2.对于int以外的类型(如float),需要声明python函数的传入参数类型,传出参数类型
fun.argtypes=[c_float,c_float] #定义传参类型 fun.restype=c_float #定义返回值类型 a=fun(c_float(1.4),c_float(1.2)) print(type(a)) print(a)
输出:
<class 'float'> 2.5999999046325684
3.对于字符串char* ,在声明传入参数类型时,需要声明为字符指针,然后分配一块char数组,最后把这个数组强制转换为字符指针
并且,在把python脚本中的数据结构导入c++中时,需要把str转换为bytes或者bytesarray类型,并且进行迭代器分解
hello=dll.HelloWorld hello.argtypes=[POINTER(c_char)] #传入参数为字符指针 STR=(c_char * 100)(*bytes("相信你还在这里",'utf-8')) #把一组100个的字符定义为STR cast(STR, POINTER(c_char)) hello(STR)
输出:
相信你还在这里
4.对于其他数据类型的数组,(例如int*),操作相似:
Ints=dll.Ints Ints.argtypes=[POINTER(c_int),c_int] INT=(c_int * 100)(*[1,2,3]) #把列表传入变长参数args*中 cast(INT, POINTER(c_int)) Ints(INT,c_int(3))
输出:
1 2 3
5.对于返回值为数组的情况,可以直接使用索引去访问,但是下标操作[]不是从迭代器中取对象,而是地址偏移:
def fillHoleCpp(im): dll = cdll.LoadLibrary("bfs.dll") bfs=dll.bfs bfs.argtypes = [POINTER(c_int),c_int] bfs.restype = POINTER(c_int) a = np.asarray(range(16), dtype=np.int32).reshape([4, 4]) if not a.flags['C_CONTIGUOUS']: a = np.ascontiguous(a, dtype=a.dtype) # 如果不是C连续的内存,必须强制转换 IMG = cast(a.ctypes.data, POINTER(c_int)) # 转换为ctypes,这里转换后的可以直接利用cty cast(IMG, POINTER(c_int)) length=a.size ans=bfs(IMG,c_int(length)) print(type(ans)) for i in range(0,length): print(ans[i],end=' ')