13

我正在为二进制格式编写解析器。这种二进制格式涉及不同的表,这些表又是二进制格式,通常包含不同的字段大小(大约在 50 到 100 个之间)。

这些结构中的大多数都将具有位域,并且在用 C 表示时看起来像这样:

struct myHeader
{
  unsigned char fieldA : 3
  unsigned char fieldB : 2;
  unsigned char fieldC : 3;
  unsigned short fieldD : 14;
  unsigned char fieldE : 4
}

我遇到了 struct 模块,但意识到它的最低分辨率是一个字节而不是一个位,否则该模块非常适合这项工作。

我知道使用 ctypes 支持位域,但我不确定如何在此处连接包含位域的 ctypes 结构。

我的另一个选择是自己操作这些位并将其输入字节并将其与 struct 模块一起使用 - 但由于我有接近 50-100 种不同类型的此类结构,因此编写代码变得更容易出错。我也担心效率,因为这个工具可能被用来解析大量的二进制数据。

谢谢。

4

2 回答 2

7

使用位(您提到您正在查看)应该很容易实现。首先创建一些要解码的数据:

>>> myheader = "3, 2, 3, 14, 4"
>>> a = bitstring.pack(myheader, 1, 0, 5, 1000, 2)
>>> a.bin
'00100101000011111010000010'
>>> a.tobytes()
'%\x0f\xa0\x80'

然后再次解码只是

>>> a.readlist(myheader)
[1, 0, 5, 1000, 2]

您主要关心的可能是速度。该库对 Python 进行了很好的优化,但速度不如 C 库快。

于 2011-08-26T10:02:46.250 回答
6

我没有对此进行严格测试,但它似乎适用于无符号类型(编辑:它也适用于有符号字节/短类型)。

编辑2:这真的是命中注定。这取决于库的编译器将位打包到结构中的方式,这不是标准化的。例如,对于 gcc 4.5.3,只要我不使用该属性来打包结构,它就可以工作,即__attribute__ ((__packed__))(因此,它不是 6 个字节,而是被打包成 4 个字节,您可以使用__alignof__and进行检查sizeof)。_pack_ = True我可以通过添加到 ctypes 结构定义来使它几乎可以工作,但是对于 fieldE 它失败了。gcc 注释:“压缩位域 'fieldE' 的偏移量在 GCC 4.4 中已更改”。

import ctypes

class MyHeader(ctypes.Structure):
    _fields_ = [
        ('fieldA', ctypes.c_ubyte, 3),
        ('fieldB', ctypes.c_ubyte, 2),
        ('fieldC', ctypes.c_ubyte, 3),
        ('fieldD', ctypes.c_ushort, 14),
        ('fieldE', ctypes.c_ubyte, 4),
    ]

lib = ctypes.cdll.LoadLibrary('C/bitfield.dll')

hdr = MyHeader()
lib.set_header(ctypes.byref(hdr))

for x in hdr._fields_:
    print("%s: %d" % (x[0], getattr(hdr, x[0])))

输出:

fieldA: 3
fieldB: 1
fieldC: 5
fieldD: 12345
fieldE: 9

C:

typedef struct _MyHeader {
    unsigned char  fieldA  :  3;
    unsigned char  fieldB  :  2;
    unsigned char  fieldC  :  3;
    unsigned short fieldD  : 14;
    unsigned char  fieldE  :  4;
} MyHeader, *pMyHeader; 

int set_header(pMyHeader hdr) {

    hdr->fieldA = 3;
    hdr->fieldB = 1;
    hdr->fieldC = 5;
    hdr->fieldD = 12345;
    hdr->fieldE = 9;

    return(0);
}
于 2011-08-26T03:22:27.273 回答