Chinaunix首页 | 论坛 | 博客

分类: Python/Ruby

2014-04-13 12:26:31


struct/union

    C 语言使用struct/union作为参数也很常见,Python提供了怎样的支持?本节分析一下。

    Structuresunions必须继承StructureUnion基础类,它们都在ctypes模块中定义,每一个子类必须定义一个 _fields_属性,_fields_是一个2tuples的列表,包含这fieldnamefieldtype. field类型必须是一个ctypes类型,像c_int,或者任何其它的继承ctypes的类型,structure,union,array,指针。 

    这里有一个简单的POINT结构,包含两个整型xy,同样它也显示了如何在构造函数中初始化一个结构。
>>> from ctypes import *
>>> class POINT(Structure):
...     _fields_ = [("x", c_int),  
...                 ("y", c_int),]             //    ("z", type(pointer(c_int())) ) 
...
>>> point = POINT(10, 20)
>>> print point.x, point.y
10 20
>>> point = POINT(y=5)                 //这种类型的赋值操作。
>>> print point.x, point.y
0 5




Structure/union对齐和byte顺序

    这个主题也是很重要的。
>>> class Int(Structure):
...     _fields_ = [("first_16", c_int, 16),          //还可以随便制定它占用的字节数,很好。
...                 ("second_16", c_int, 16)]
...
>>> print Int.first_16

>>> print Int.second_16
16, bits=16>        //一个字节,分成多个段的情况下使用
>>>
     我们为Int的每个数据成员都指定了它的长度, 但是这并不代表就对齐了。C语言中因对齐忽略的字节,需要在Python中进行类似的("second_16", c_int, 16)的声明吗?注意默认Structure/unionfield对齐和c编译器的方式相同,所以应该不需要。
    还有就是first和second在内存中的相对关系,也是大小端的关系。
ctypes使用结构和联合原始的byte顺序(原始的byte顺序是什么)。使用一个非原始的byte顺序创建结构,你可以使用BigEndianStructure, LittleEndianStructureBigEndianUnionLittleEndianUnion中的一个作为基础类。

未完成的类型定义

    直接转换为ctypes像这样,但是它不能工作: 

>>> class cell(Structure):

...     _fields_ = [("name", c_char_p),

...                 ("next", POINTER(cell))]

...

Traceback (most recent call last):

  File "", line 1, in ?

  File "", line 2, in cell

NameError: name 'cell' is not defined

>>>


    但是,新类cell在它自己的类声明中是无效的。在ctypes,可以定义cell类,同时在类声明中设置_fields_属性

>>> from ctypes import *

>>> class cell(Structure):

...     pass

...

>>> cell._fields_ = [("name", c_char_p),

...                  ("next", POINTER(cell))]             //应该使用这种形式呀!!

>>>


尝试一下,我们可以创建cell的两个实例,让他们指向他们自己。

>>> c1 = cell()

>>> c1.name = "foo"

>>> c2 = cell()

>>> c2.name = "bar"

>>> c1.next = pointer(c2)

>>> c2.next = pointer(c1)

>>> p = c1

>>> for i in range(8):

...     print p.name,

...     p = p.next[0]

...

foo bar foo bar foo bar foo bar

>>> 


强制类型转换

        使用cast函数将一个ctypes实例转换成一个不同的ctypes数据类型的指针cast对象有两个参数,一个ctypes对象是或者可以转换成某些类型的指针,或一个ctypes指针类型。它返回这第二个参数的实例,它引用第一个参数相同的内存块。 

>>> a = (c_byte * 4)() 
>>> cast(a, POINTER(c_int))           //参数2应该是一个类型。
 
>>> 

阅读(2244) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~