【问题标题】:How Do I Properly Declare a ctype Structure + Union in Python?如何在 Python 中正确声明 ctype 结构 + 联合?
【发布时间】:2012-05-07 22:48:40
【问题描述】:

我正在制作一个二进制数据解析器,虽然我可以使用 C,但我想看看我是否可以使用 Python 来完成这项任务。

我对如何实现这一点有了一些了解,我当前的实现看起来像这样:

from ctypes import *

class sHeader(Structure):
    _fields_ = [("CC", c_uint8, 4),
            ("AFC", c_uint8, 2),
            ("TSC", c_uint8, 2),
            ("PID", c_uint16, 13),
            ("TP", c_uint16, 1),
            ("PSI", c_uint16, 1),
            ("TEI", c_uint16, 1),
            ("SyncByte", c_uint8)]

class Header(Union):
    _fields_ = [("sData", sTsHeader),
            ("ulData", c_uint32)]

head = Header()
head.ulData = 0xffffffff
print(head.ulData)
print(head.sData.SyncByte)

print(sHeader.SyncByte)
print(sHeader.TEI)
print(sHeader.PSI)
print(sHeader.TP)
print(sHeader.PID)
print(sHeader.TSC)
print(sHeader.AFC)
print(sHeader.CC)


print(sizeof(sHeader))
print(sizeof(c_uint8))
print(sizeof(c_uint16))
print(sizeof(c_uint32))

产生这个输出:

V:\>C:\Python27\python.exe WidiUnpacker.py
0xffffffffL
0x0
<Field type=c_ubyte, ofs=4, size=1>
<Field type=c_ushort, ofs=2:15, bits=1>
<Field type=c_ushort, ofs=2:14, bits=1>
<Field type=c_ushort, ofs=2:13, bits=1>
<Field type=c_ushort, ofs=2:0, bits=13>
<Field type=c_ubyte, ofs=0:6, bits=2>
<Field type=c_ubyte, ofs=0:4, bits=2>
<Field type=c_ubyte, ofs=0:0, bits=4>
6
1
2
4

所以...在我看来,我的字节与其说是字不如说是字节。我对 Python 或 ctypes 的了解不够多,无法理解为什么会这样,但这有点违背了我目前的目的。有什么想法吗?

【问题讨论】:

    标签: python struct byte ctypes unions


    【解决方案1】:

    您可以使用_pack_ 类属性控制对齐方式:

    class sHeader(Structure):
        _pack_ = 1
    

    结果

    4294967295
    255
    <Field type=c_ubyte, ofs=3, size=1>
    <Field type=c_ushort, ofs=1:15, bits=1>
    <Field type=c_ushort, ofs=1:14, bits=1>
    <Field type=c_ushort, ofs=1:13, bits=1>
    <Field type=c_ushort, ofs=1:0, bits=13>
    <Field type=c_ubyte, ofs=0:6, bits=2>
    <Field type=c_ubyte, ofs=0:4, bits=2>
    <Field type=c_ubyte, ofs=0:0, bits=4>
    4
    1
    2
    4
    

    【讨论】:

    • 刚刚在一个 48 位的结构上试了一下,效果很好。
    【解决方案2】:

    您的sHeader 有一个 4 位字段,然后是一个 2 位字段,然后是一个 2 位字段(总共 8 位 = 1 个字节)...但是下一项是需要对齐的 c_uint16在 2 字节边界上,因此跳过一个字节并移动到字节 2,然后再占用 13 位。

    如果您不想要(显然您不想要),只需将所有内容设为 c_uint32 或类似名称:

    from ctypes import *
    
    class sHeader(Structure):
        _fields_ = [("CC", c_uint32, 4),
            ("AFC", c_uint32, 2),
            ("TSC", c_uint32, 2),
            ("PID", c_uint32, 13),
            ("TP", c_uint32, 1),
            ("PSI", c_uint32, 1),
            ("TEI", c_uint32, 1),
            ("SyncByte", c_uint32, 8)] # note: added 8 here
    
    print sHeader.PID
    print sHeader.SyncByte
    

    结果:

    <Field type=c_uint, ofs=0:8, bits=13>
    <Field type=c_uint, ofs=0:24, bits=8>
    

    (我选择 uint32 是因为你的位字段加起来是 32 位。我在这里使用的是 Python 2.7,因此prints 上没有括号。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-12
      • 2011-07-02
      • 2015-10-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多