ctypes是python的一个函数库,提供和C语言兼容的数据类型,可以直接调用动态链接库中的导出函数。
为了使用ctypes,必须依次完成以下步骤:
加载动态链接库
将python对象转换成ctypes所能识别的参数
使用ctypes所能识别的参数调用动态链接库中的函数
动态链接库加载方式有三种:
cdll
windll
oledll
它们的不同之处在于:动态链接库中的函数所遵守的函数调用方式(calling convention)以及返回方式有所不同。
cdll用于加载遵循cdecl调用约定的动态链接库,windll用于加载遵循stdcall调用约定的动态链接库,oledll与windll完全相同,只是会默认其载入的函数统一返回一个Windows HRESULT错误编码。
函数调用约定:函数调用约定指的是函数参数入栈的顺序、哪些参数入栈、哪些通过寄存器传值、函数返回时栈帧的回收方式(是由调用者负责清理,还是被调用者清理)、函数名称的修饰方法等等。常见的调用约定有cdecl和stdcall两种。在《程序员的自我修养--链接、装载与库》一书的第10章有对函数调用约定的更详细介绍。
cdecl规定函数参数列表以从右到左的方式入栈,且由函数的调用者负责清除栈帧上的参数。stdcall的参数入栈方式与cdecl一致,但函数返回时是由被调用者自己负责清理栈帧。而且stdcall是Win32 API函数所使用的调用约定。
例子:
Linux下:
或者:
其他例子:
一个完整的例子:
1,编写动态链接库
//filename: foo.c
#include"stdio.h"
char* myprint(char *str)
{
puts(str);returnstr;
}float add(float a, floatb)
{return a +b;
}
将foo.c编译为动态链接库:
gcc -fPIC -shared foo.c -o foo.so
2.使用ctypes调用foo.so
#coding:utf8
#FILENAME:foo.py
from ctypes import *foo= CDLL('./foo.so')
myprint=foo.myprint
myprint.argtypes= [POINTER(c_char)] #参数类型为char指针
myprint.restype = c_char_p #返回类型为char指针
res = myprint('hello ctypes')print(res)
add=foo.add
add.argtype