Python调用C/C++动态链接库的方法详解
本文以实例讲解了python调用c/c++ dll动态链接库的方法,具体示例如下:
示例一:
首先,在创建一个dll工程(本例创建环境为vs 2005),头文件:
//hello.h #ifdef export_hello_dll #define hello_api __declspec(dllexport) #else #define hello_api __declspec(dllimport) #endif extern "c" { hello_api int intadd(int , int); }
cpp文件:
//hello.cpp #define export_hello_dll #include "hello.h" hello_api int intadd(int a, int b) { return a + b; }
这里有两个注意点:
(1)弄清楚编译的时候函数的调用约定采用的__cdecl还是__stdcall,因为根据dll中函数调用约定方式,python将使用相应的函数加载dll。
(2)如果采用c++的工程,那么导出的接口需要extern "c",这样python中才能识别导出的函数。
我的工程中采用__cdecl函数调用约定方式进行编译链接产生hello.dll,然后python中采用ctypes库对hello.dll进行加载和函数调用:
from ctypes import * dll = cdll.loadlibrary('hello.dll'); ret = dll.intadd(2, 4); print ret;
至此,第一个小例子已经完成了,读者可以自己动手尝试一下运行效果。
示例二:
示例一只是一个"hello world"级别的程序,实际运用中更多的需要传递数据结构、字符串等,才能满足我们的需求。那么本示例将展示,如何传递数据结构参数,以及如何通过数据结构获取返回值。
首先编写dll工程中的头文件:
//hello.h #ifdef export_hello_dll #define hello_api __declspec(dllexport) #else #define hello_api __declspec(dllimport) #endif #define array_number 20 #define str_len 20 struct structtest { int number; char* pchar; char str[str_len]; int iarray[array_number]; }; extern "c" { //hello_api int intadd(int , int); hello_api char* getstructinfo(struct structtest* pstruct); }
cpp文件如下:
//hello.cpp #include <string.h> #define export_hello_dll #include "hello.h" hello_api char* getstructinfo(struct structtest* pstruct) { for (int i = 0; i < array_number; i++) pstruct->iarray[i] = i; pstruct->pchar = "hello python!"; strcpy (pstruct->str, "hello world!"); pstruct->number = 100; return "just ok"; }
getstructinfo这个函数通过传递一个structtest类型的指针,然后对对象中的属性进行赋值,最后返回"just ok".
编写python调用代码如下,首先在python中继承structure构造一个和c dll中一致的数据结构structtest,然后设置函数getstructinfo的参数类型和返回值类型,最后创建一个structtest对象,并将其转化为指针作为参数,调用函数getstrcutinfo,最后通过输出数据结构的值来检查是否调用成功:
from ctypes import * array_number = 20; str_len = 20; #define type intarray20 = c_int * array_number; chararray20 = c_char * str_len; #define struct class structtest(structure): _fields_ = [ ("number", c_int), ("pchar", c_char_p), ("str", chararray20), ("iarray", intarray20) ] #load dll and get the function object dll = cdll.loadlibrary('hello.dll'); getstructinfo = dll.getstructinfo; #set the return type getstructinfo.restype = c_char_p; #set the argtypes getstructinfo.argtypes = [pointer(structtest)]; objectstruct = structtest(); #invoke api getstructinfo retstr = getstructinfo(byref(objectstruct)); #check result print "number: ", objectstruct.number; print "pchar: ", objectstruct.pchar; print "str: ", objectstruct.str; for i,val in enumerate(objectstruct.iarray): print 'array[i]: ', val; print retstr;
总结:
1. 用64位的python去加载32位的dll会出错
2. 以上只是些测试程序,在编写python过程中尽可能的使用"try except"来处理异常
3. 注意在python与c dll交互的时候字节对齐问题
4. ctypes库的功能还有待继续探索