一直对不同语言间的交互感兴趣,python 和 C 语言又深有渊源,所以对 python 和 c 语言交互产生了兴趣。
最近了解了 python 提供的一个外部函数库
, 它提供了 C 语言兼容的几种数据类型,并且可以允许调用 C 编译好的库。 这里是阅读相关资料的一个记录,内容大部分来自。
- ctypes
提供了一些原始的 C 语言兼容的数据类型,参见下表, 其中第一列是在 ctypes 库中定义的变量类型,第二列是 C 语言定义的变量类型,第三列是 Python 语言在不使用 ctypes 时定义的变量类型。
- ctypes
- | ctypes type | C type | Python type | |--------------+----------------------------------------+----------------------------||c_bool | _Bool | bool(1) | |c_char | char | 1 - character string | |c_wchar | wchar_t | 1 - character unicode string | |c_byte | char | int / long | |c_ubyte | unsigned char | int / long | |c_short | short | int / long | |c_ushort | unsigned short | int / long | |c_int | int | int / long | |c_uint | unsigned int | int / long | |c_long | long | int / long | |c_ulong | unsigned long | int / long | |c_longlong | __int64 or long long | int / long | |c_ulonglong | unsigned __int64 or unsigned long long | int / long | |c_float | float | float | |c_double | double | float | |c_longdouble | long double | float | |c_char_p | char * (NUL terminated) | string or None | |c_wchar_p | wchar_t * (NUL terminated) | unicode or None | |c_void_p | void * |int / long or None |
创建简单的 ctypes 类型如下:
- >>> c_int() c_long(0) >>> c_char_p("Hello, World") c_char_p('Hello, World') >>> c_ushort( - 3) c_ushort(65533) >>>
使用
访问和改变值:
- .value
- >>> i = c_int(42) >>> print i c_long(42) >>> print i.value 42 >>> i.value = -99 >>> print i.value - 99 >>>
改变指针类型的变量值:
- >>> 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#一开始赋值的字符串并不会改变,因为这里指针的实例改变的是指向的内存地址,不是直接改变内存里的内容Hello,
- World >>>
如果需要直接操作内存地址的数据类型:
- >>> 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)#.raw访问内存里存储的内容6 'Hello\x00' >>> print repr(p.value)#.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 的数组和结构体:
- >>> class POINT(Structure) : #定义一个结构,内含两个成员变量x,y,均为int型..._fields_ = [("x", c_int), ... ("y", c_int)]... >>> point = POINT(2, 5)#定义一个POINT类型的变量,初始值为x = 2,
- y = 5 >>> print point.x,
- point.y#打印变量2 5 >>> point = POINT(y = 5)#重新定义一个POINT类型变量,x取默认值 >>> print point.x,
- point.y#打印变量0 5 >>> POINT_ARRAY = POINT * 3#定义POINT_ARRAY为POINT的数组类型#定义一个POINT数组,内含三个POINT变量 >>> pa = POINT_ARRAY(POINT(7, 7), POINT(8, 8), POINT(9, 9)) >>>
- for p in pa: print p.x,
- p.y#打印POINT数组中每个成员的值...7 7 8 8 9 9
创建指针实例
- >>> from ctypes import * >>>i = c_int(42) >>> pi = pointer(i) >>> >>>pi.contents c_long(42) >>>
使用 cast() 类型转换
- >>> class Bar(Structure) : ..._fields_ = [("count", c_int), ("values", POINTER(c_int))]... >>> bar = Bar() >>> bar.values = (c_int * 3)(1, 2, 3) >>> bar.count = 3 >>>
- for i in range(bar.count) : ...print bar.values[i]...1 2 3 >>> >>>bar = Bar() >>> bar.values = cast((c_byte * 4)(), POINTER(c_int))#这里转成需要的类型 >>> print bar.values[0] 0 >>>
类似于 C 语言定义函数时,会先定义返回类型,然后具体实现再定义,当遇到下面这种情况时,也需要这么干:
- >>> class cell(Structure) : ..._fields_ = [("name", c_char_p), ... ("next", POINTER(cell))]...Traceback(most recent call last) : File "<stdin>",
- line 1,
- in?File "<stdin>",
- line 2,
- incell NameError: name 'cell'is not defined >>> #不能调用自己,所以得像下面这样 >>> from ctypes import * >>>class cell(Structure) : ...pass... >>> cell._fields_ = [("name", c_char_p), ... ("next", POINTER(cell))] >>>
可以简单地将 "so" 和 "dll" 理解成 Linux 和 windows 上动态链接库的指代,这里我们以 Linux 为例。注意,ctypes 提供的接口会在不同系统上有出入,比如为了加载动态链接库, 在 Linux 上提供的是
, 而在 Windows 上提供的是
- cdll
和
- windll
。
- oledll
- from ctypes import * >>>cdll.LoadLibrary("libc.so.6") < CDLL 'libc.so.6',
- handle...at... > >>>libc = CDLL("libc.so.6") >>> libc < CDLL 'libc.so.6',
- handle...at... > >>>
- >>> print libc.time(None) 1150640792 >>> print hex(windll.kernel32.GetModuleHandleA(None)) 0x1d000000 >>>
ctypes 会寻找
属性来用作调用函数的参数传入,这样就可以传入自己定义的类作为参数,示例如下:
- _as_paramter_
- >>> class Bottles(object) : ...def __init__(self, number) : ...self._as_parameter_ = number... >>> bottles = Bottles(42) >>> printf("%d bottles of beer\n", bottles) 42 bottles of beer 19 >>>
用
和
- argtypes
来指定调用的函数返回类型。
- restype
- >>> printf.argtypes = [c_char_p, c_char_p, c_int, c_double] >>> printf("String '%s', Int %d, Double %f\n", "Hi", 10, 2.2) String 'Hi',
- Int 10,
- Double 2.200000 37 >>> >>>strchr = libc.strchr >>> strchr("abcdef", ord("d")) 8059983 >>> strchr.restype = c_char_p#c_char_p is a pointer to a string >>> strchr("abcdef", ord("d"))'def' >>> print strchr("abcdef", ord("x")) None >>>
这里我只是列出了
最基础的部分,还有很多细节请参考官方文档。
- ctypes
这两天文章没有写,先是早出晚归出去玩了一整天,然后加班到凌晨 3 点左右,一天一篇计划划水得严重啊…
来源: http://www.cnblogs.com/nisen/p/6120325.html