在python中实现C的枚举和联合

时间:2010-09-28 16:27:54

标签: python c struct unions

我正在尝试找出一些C代码,以便将其移植到python中。该代码用于读取专有的二进制数据文件格式。到目前为止它一直很简单 - 它主要是结构体,我一直在使用struct库从文件中请求特定的ctypes。但是,我刚刚提到了这段代码,我对如何在python中实现它感到茫然。特别是,我不确定如何处理enumunion

#define BYTE char 
#define UBYTE unsigned char 
#define WORD short 
#define UWORD unsigned short

typedef enum {
    TEEG_EVENT_TAB1=1, 
    TEEG_EVENT_TAB2=2
} TEEG_TYPE;

typedef struct
{
        TEEG_TYPE Teeg;
        long Size;
    union

        {
            void *Ptr;  // Memory pointer
            long Offset
        };
} TEEG;

其次,在下面的结构定义中,我不确定变量名后面的冒号是什么意思,(例如,KeyPad:4)。这是否意味着我应该读4个字节?

typedef struct
{
    UWORD StimType;
    UBYTE KeyBoard;
    UBYTE KeyPad:4;
    UBYTE Accept:4;
    long Offset;
} EVENT1;

如果它有用,我在python中访问文件的方式的抽象示例如下:

from struct import unpack, calcsize

def get(ctype, size=1):
    """Reads and unpacks binary data into the desired ctype."""
    if size == 1:
        size = ''
    else:
        size = str(size)

    chunk = file.read(calcsize(size + ctype))
    return unpack(size + ctype, chunk)[0]

file = open("file.bin", "rb")
file.seek(1234)

var1 = get('i')
var2 = get('4l')
var3 = get('10s')

4 个答案:

答案 0 :(得分:8)

枚举:该语言中没有枚举。已经提出了各种习语,但没有一种真正普遍存在。最直接的(在这种情况下是足够的)解决方案是

TEEG_EVENT_TAB1 = 1
TEEG_EVENT_TAB2 = 2

工会:ctypesunions

fieldname : n语法称为位域,是的,的意思是“这是n位大”。同样,ctypes有them

答案 1 :(得分:2)

我不知道你所有问题的答案,但是对于你不需要按值查找的枚举,(只是用它来避免魔术数字),我喜欢用一个小的类。常规字典是另一种可行的选择。如果您需要按值查找,则可能需要其他结构。

class TeegType(object):
    TEEG_EVENT_TAB1 = 1
    TEEG_EVENT_TAB2 = 2

print TeegType.TEEG_EVENT_TAB1

答案 2 :(得分:0)

您真正需要知道的是:

  1. What is the size of an enum?。您将使用此答案生成解包代码。
  2. What is the size of a union?。总结:最大成员的规模。
  3. 你如何处理指针?你应该看一下ctypes模块。对于您正在做的事情,它可能比struct模块更容易使用。特别是,它可以使用通过C到达的指针。
  4. 如何将从结构中读取的数据强制/转换为正确的类型以便在python中使用?这就是我在上面的子弹中推荐ctypes的原因;该模块具有执行必要演员表的功能。

答案 3 :(得分:0)

C enum声明是一种围绕某种整数类型的语法包装。见Is the sizeof(enum) == sizeof(int), always?int的大小取决于特定的C编译器。我可能会尝试16位。

union保留一个内存块,其大小与包含的最大数据类型相同。同样,确切的大小将取决于C实现,但我希望32位架构为32位,如果将其编译为本机64位代码,则为64位。一般来说,您可以将union的内容存储在Python整数或长整数中,无论其中保存的内容是指针还是偏移量。

一个更有趣的问题是为什么指针会被写入磁盘文件。您可能会发现union字段仅在TEEG struct在内存中时被视为指针,但在写入磁盘时,它始终是整数偏移量。

至于:4符号,正如几个人所指出的,这些是“位字段”,意思是一系列位,其中几个可以打包到一个空格中。如果我没记错的话,C中的位域被打包到int s中,因此这两个4位字段都将打包成一个整数。它们可以通过适当使用Python的“&”解压缩(按位和)和“>>” (右移)运营商。同样,字段如何打包到整数中,以及整数字段本身的大小将取决于特定的C实现。

以下代码段可能会对您有所帮助:

SIZEOF_TEEG_TYPE = 2      # First guess for enum is two bytes
FMT_TEEG_TYPE = "h"       # Could be "b", "B", "h", "H", "l", "L", "q" or "Q"

SIZEOF_LONG = 4           # Use 8 in 64-bit Unix architectures
FMT_LONG = "l"            # Use "q" in 64-bit Unix architectures
                          # Life gets more interesting if you are reading 64-bit
                          # using 32-bit Python

SIZEOF_PTR_LONG_UNION = 4 # Use 8 in any 64-bit architecture
FMT_PTR_LONG_UNION = "l"  # Use "q" in any 64-bit architecture
                          # Life gets more interesting if you are reading 64-bit
                          # using 32-bit Python

SIZEOF_TEEG_STRUCT = SIZEOF_TEEG_TYPE + SIZEOF_LONG + SIZEOF_PTR_LONG_UNION
FMT_TEEG_STRUCT = FMT_TEEG_TYPE + FMT_LONG + FMT_PTR_LONG_UNION


# Constants for TEEG_EVENTs
TEEG_EVENT_TAB1 = 1
TEEG_EVENT_TAB2 = 2

.
.
.

# Read a TEEG structure
teeg_raw = file_handle.read( SIZEOF_TEEG_STRUCT )
teeg_type, teeg_size, teeg_offset = struct.unpack( FMT_TEEG_STRUCT, teeg_raw )

.
.
.

# Use TEEG_TYPE information
if teeg_type == TEEG_EVENT_TAB1:
    Do something useful

elif teeg_type == TEEG_EVENT_TAB2:
    Do something else useful

else:
    raise ValueError( "Encountered illegal TEEG_EVENT type %d" % teeg_type )
相关问题