Как правильно объявить структуру ctype + Union в Python?
я возился с созданием парсера двоичных данных, и хотя я мог бы вернуться на 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:Python27python.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, чтобы понять, почему это так, но это что-то вроде поражения моей цели на данный момент. Есть идеи?
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 здесь, следовательно, нет скобок на print
s.)
вы можете управлять выравниванием с _pack_
атрибута class:
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