温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

python ctypes的作用有哪些

发布时间:2020-09-21 14:32:46 来源:亿速云 阅读:696 作者:Leah 栏目:编程语言

这篇文章将为大家详细讲解有关python ctypes的作用有哪些,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

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下:

python ctypes的作用有哪些

或者:

python ctypes的作用有哪些

其他例子:

python ctypes的作用有哪些

一个完整的例子:

1.编写动态链接库

// filename: foo.c #include "stdio.h" char* myprint(char *str) {     puts(str);     return str; } float add(float a, float b) {     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.argtypes = [c_float, c_float] # 参数类型为两个float add.restype = c_float # 返回类型为float print(add(1.3, 1.2))

执行:

[jingjiang@iZ255w0dc5eZ test]$ python2.6 foo.py  hello ctypes hello ctypes 2.5

ctypes数据类型和C数据类型对照表

python ctypes的作用有哪些

查找动态链接库

>>> from ctypes.util import find_library >>> find_library("m") 'libm.so.6' >>> find_library("c") 'libc.so.6' >>> find_library("bz2") 'libbz2.so.1.0'

函数返回类型

函数默认返回 C int 类型,如果需要返回其他类型,需要设置函数的 restype 属性。

>>> from ctypes import * >>> from ctypes.util import find_library >>> libc = cdll.LoadLibrary(find_library("c")) >>> strchr = libc.strchr >>> strchr("abcdef", ord("d")) -808023673 >>> strchr.restype = c_char_p >>> strchr("abcdef", ord("d")) 'def' >>> strchr("abcdef", ord("x"))

回调函数

·定义回调函数类型,类似于c中的函数指针,比如:void (*callback)(void* arg1, void* arg2),定义为:callack = CFUNCTYPE(None, cvoidp, cvoidp)

None表示返回值是void,也可以是其他类型。剩余的两个参数与c中的回调参数一致。

·定义python回调函数:

def _callback(arg1, arg2):     #do sth     # ...     #return sth

·注册回调函数:

cb = callback(_callback)

另外,使用ctypes可以避免GIL的问题。

一个例子:

//callback.c #include "stdio.h" void showNumber(int n, void (*print)()) {     (*print)(n); }

编译成动态链接库:

gcc -fPIC -shared -o callback.so callback.c

编写测试代码:

#FILENAME:callback.py from ctypes import * _cb = CFUNCTYPE(None, c_int) def pr(n):     print 'this is : %d' % n  cb = _cb(pr) callback = CDLL("./callback.so") showNumber = callback.showNumber showNumber.argtypes = [c_int, c_void_p] showNumber.restype = c_void_p for i in range(10):     showNumber(i, cb)

执行:

$ python2.7 callback.py  this is : 0  this is : 1  this is : 2  this is : 3  this is : 4  this is : 5  this is : 6  this is : 7  this is : 8  this is : 9

 结构体和联合

union(联合体 共用体) 1、union中可以定义多个成员,union的大小由最大的成员的大小决定。  2、union成员共享同一块大小的内存,一次只能使用其中的一个成员。  3、对某一个成员赋值,会覆盖其他成员的值(也不奇怪,因为他们共享一块内存。但前提是成员所占字节数相同, 当成员所占字节数不同时只会覆盖相应字节上的值,>比如对char成员赋值就不会把整个int成员覆盖掉,因为char只占一个字节, 而int占四个字节) 4、联合体union的存放顺序是所有成员都从低地址开始存放的。

结构体和联合必须从Structure和Union继承,子类必须定义__fields__属性,__fields__属性必须是一个二元组的列表,包含field的名称和field的类型,field类型必须是一个ctypes的类型,例如:c_int, 或者其他继承自ctypes的类型,例如:结构体,联合,数组,指针。

from ctypes import * class Point(Structure):     __fields__ = [         ("x", c_int),         ("y", c_int),     ]        def __str__(self):         return "x={0.x}, y={0.y}".format(self) point1 = Point(x=10, y=20) print "point1:", point1 class Rect(Structure):     __fields__ = [          ("upperleft", Point),         ("lowerright", Point),     ]        def __str__(self):         return "upperleft:[{0.upperleft}], lowerright:[{0.lowerright}]".format(self) rect1 = Rect(upperleft=Point(x=1, y=2), lowerright=Point(x=3, y=4)) print "rect1:", rect1

运行:

python test.py  point1: x=10, y=20 rect1: upperleft:[x=1, y=2], lowerright:[x=3, y=4]

数组

数组定义很简单,比如:定义一个有10个Point元素的数组,

TenPointsArrayType = Point * 10。

初始化和使用数组:

from ctypes import * TenIntegersArrayType = c_int * 10 array1 = TenIntegersArrayType(*range(1, 11))print array1 for i in array1:     print i

运行:

$ python2.7 array.py <__main__.c_int_Array_10 object at 0x7fad0d7394d0> 1 2 3 4 5 6 7 8 9 10

指针

pointer()可以创建一个指针,Pointer实例有一个contents属性,返回指针指向的内容。

>>> from ctypes import * >>> i = c_int(42) >>> p = pointer(i) >>> p<__main__.LP_c_int object at 0x7f413081d560> >>> p.contents c_int(42) >>>

可以改变指针指向的内容

>>> i = c_int(99) >>> p.contents = i >>> p.contents c_int(99)

可以按数组的方式访问,并改变值

>>> p[0] 99 >>> p[0] = 22 >>> i c_int(22)

传递指针或引用

很多情况下,c函数需要传递指针或引用,ctypes也完美支持这一点。

byref()用来传递引用参数,pointer()也可以完成同样的工作,但是pointer会创建一个实际的指针对象,如果你不需要一个指针对象,用byref()会快很多。

>>> from ctypes import * >>> i = c_int() >>> f = c_float() >>> s = create_string_buffer('\000' * 32) >>> print i.value, f.value, repr(s.value) 0 0.0 '' >>> libc = CDLL("libc.so.6") >>> libc.sscanf("1 3.14 Hello", "%d %f %s", byref(i), byref(f), s) 3    >>> print i.value, f.value, repr(s.value) 1 3.1400001049 'Hello'

可改变内容的字符串

如果需要可改变内容的字符串,需要使用 createstringbuffer()

>>> from ctypes import * >>> p = create_string_buffer(3)      # create a 3 byte buffer,  initialized to NUL bytes >>> print sizeof(p), repr(p.raw) 3 '/x00/x00/x00'>>> p = create_string_buffer("Hello")      # create a buffer containing a NUL terminated string >>> print sizeof(p), repr(p.raw) 6 'Hello/x00' >>> print repr(p.value) 'Hello' >>> p = create_string_buffer("Hello", 10)  # create a 10 byte buffer >>> print sizeof(p), repr(p.raw) 10 'Hello/x00/x00/x00/x00/x00' >>> p.value = "Hi" >>> print sizeof(p), repr(p.raw) 10 'Hi/x00lo/x00/x00/x00/x00/x00' >>>

赋值给c_char_p,c_wchar_p,c_void_p

只改变他们指向的内存地址,而不是改变内存的内容

>>> s = "Hello, World" >>> c_s = c_char_p(s) >>> print c_s c_char_p('Hello, World')>>> c_s.value = "Hi, there" >>> print c_s c_char_p('Hi, there') >>> print s                 # first string is unchanged Hello, World >>>

数据都可以改变

>>> i = c_int(42) >>> print i c_long(42) >>> print i.value42 >>> i.value = -99 >>> print i.value -99 >>>

关于python ctypes的作用有哪些就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI