4

我试图找出一些 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 中访问文件的方式的抽象示例如下:

从结构导入解包,计算大小

def get(ctype, size=1):
    """读取二进制数据并将其解压缩为所需的 ctype。"""
    如果大小 == 1:
        大小 = ''
    别的:
        大小 = str(大小)

    chunk = file.read(calcsize(size + ctype))
    返回解包(大小 + ctype,块)[0]

文件 = 打开(“文件.bin”,“rb”)
文件.seek(1234)

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

4

4 回答 4

8

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

TEEG_EVENT_TAB1 = 1
TEEG_EVENT_TAB2 = 2

工会:ctypes工会

fieldname : n语法称为位域,是的,确实意味着“这是 n 位大”。同样, ctypes 有它们

于 2010-09-28T16:39:06.047 回答
2

我不知道您所有问题的答案,但是对于您不需要按值查找的枚举(即,只是使用它来避免幻数),我喜欢使用一个小班。常规 dict 是另一种可以正常工作的选项。如果您需要按值查找,则可能需要另一种结构。

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

print TeegType.TEEG_EVENT_TAB1
于 2010-09-28T16:37:04.590 回答
0

你真正需要知道的是:

  1. 枚举的大小是多少?. 您将使用此答案生成您的解包代码。
  2. 工会的规模是多少?. 总结:最大成员的大小。
  3. 你如何处理那个指针?你应该看看这个ctypes模块。对于您正在做的事情,它可能比struct模块更容易使用。特别是,它可以处理通过 C 到达的指针。
  4. 您如何强制/将从结构读取的数据转换为正确的类型以在 python 中使用?这就是我ctypes在上面的项目符号中推荐的原因;该模块具有执行必要转换的功能。
于 2010-09-28T17:23:09.157 回答
0

Cenum声明是一些整数类型的语法包装。请参阅sizeof(enum) == sizeof(int),总是吗?. an 的int大小取决于特定的 C 编译器。我可能会从尝试 16 位开始。

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

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

至于 :4 表示法,正如一些人所指出的,这些是“位域”,意思是一个位序列,其中几个位可以打包到一个空间中。如果我没记错的话,C 中的位域被打包成ints,所以这两个 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 )
于 2010-09-28T17:28:48.133 回答