原本的机器学习项目都用python写好,老板这边又出了个新需求,将部分核心代码抽出来,用C编写,然后通过dll的方式引用,目的就是为了隐藏部分核心代码。
1. 编写C代码
使用codeblocks建dll库
- 选择ddl
- main.c编写要导出的函数
1 |
|
- main.h 编写导出头文件(默认)
1 |
|
- 编译
编译成功后在对应文件夹bin/Debug生成dll文件
2 C调用dl
新建Console Application
main.c代码编写
注意点:
- 导入头文件”windows.h”
- 函数定义 typedef int (*addInt)(int,int);
- 导入DLL: HMODULE LoadLibrary
- 获得dll的函数:add_int = (addInt)GetProcAddress(hDll, “add_int”);
- FreeLibrary
- 若c参数为二维指针,需要两次malloc
1 |
|
3 Python调用Dll
- 下载与导入ctypes包
1 | from ctypes import cdll,c_float,c_int |
导入dll
1
mykernel = cdll.LoadLibrary('dll路径')
要调用的C函数参数(argtypes)与返回值(restype)都有二维指针,因此需要预先设置
npct.ndpointer表示是指针
1
2
3
4
5
6
7mykernel.Kernel.argtypes = [npct.ndpointer(dtype=np.float64,ndim=2,shape = (2, 3),flags='C_CONTIGUOUS'),
npct.ndpointer(dtype=np.float64,ndim=2,shape = (2, 3),flags='C_CONTIGUOUS'),
c_int,
c_int,
c_float,
npct.ndpointer(dtype=np.float64,ndim=1,flags='C_CONTIGUOUS')]
mykernel.Kernel.restype = npct.ndpointer(dtype=np.float64,ndim=2,shape = (2, 3),flags='C_CONTIGUOUS')numpy数组
1 | x=[[1,2,3],[4,5,6]] |
- 调用函数
1 | res = mykernel.Kernel(x,x,x.shape[0],x.shape[1],c_float(0.1),w) |
- Free
1 | win32api.FreeLibrary(mykernel._handle) |
一个大坑:
python的float32要对应C的float类型,float64对应 double类型,否则会造成地址访问冲突
具体报错:exception: access violation reading 0xFFFFFFFFFFFFFFFF