我正在尝试找出一些C代码,以便将其移植到python中。该代码用于读取专有的二进制数据文件格式。到目前为止它一直很简单 - 它主要是结构体,我一直在使用struct
库从文件中请求特定的ctypes。但是,我刚刚提到了这段代码,我对如何在python中实现它感到茫然。特别是,我不确定如何处理enum
或union
。
#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')
答案 0 :(得分:8)
枚举:该语言中没有枚举。已经提出了各种习语,但没有一种真正普遍存在。最直接的(在这种情况下是足够的)解决方案是
TEEG_EVENT_TAB1 = 1
TEEG_EVENT_TAB2 = 2
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)
您真正需要知道的是:
ctypes
模块。对于您正在做的事情,它可能比struct
模块更容易使用。特别是,它可以使用通过C到达的指针。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 )