struct.error: для распаковки требуется строковый аргумент длиной 4 - PullRequest
21 голосов
/ 10 апреля 2010

Python говорит, что мне нужно 4 байта для кода формата "BH":

struct.error: unpack requires a string argument of length 4

Вот код, я вставляю 3 байта, как мне кажется, необходимо:

major, minor = struct.unpack("BH", self.fp.read(3))

"B" Беззнаковый символ (1 байт) + "H" Беззнаковый короткий (2 байта) = 3 байта (!?)

struct.calcsize ("BH") говорит 4 байта.

РЕДАКТИРОВАТЬ: файл ~ 800 МБ, и это в первых нескольких байтах файла, поэтому я вполне уверен, что есть данные, которые нужно прочитать.

Ответы [ 2 ]

22 голосов
/ 10 апреля 2010

Модуль struct имитирует C-структуры. Процессору требуется больше циклов ЦП, чтобы прочитать 16-разрядное слово по нечетному адресу или 32-разрядное слово по адресу, не делимому на 4, поэтому структуры добавляют «байты заполнения», чтобы элементы структуры попадали на естественные границы. Рассмотрим:

struct {                   11
    char a;      012345678901
    short b;     ------------
    char c;      axbbcxxxdddd
    int d;
};

Эта структура будет занимать 12 байтов памяти (x - это байты pad).

Python работает аналогично (см. Документацию struct ):

>>> import struct
>>> struct.pack('BHBL',1,2,3,4)
'\x01\x00\x02\x00\x03\x00\x00\x00\x04\x00\x00\x00'
>>> struct.calcsize('BHBL')
12

Компиляторы обычно имеют способ устранения дополнения. В Python любой из = <>! исключит заполнение:

>>> struct.calcsize('=BHBL')
8
>>> struct.pack('=BHBL',1,2,3,4)
'\x01\x02\x00\x03\x04\x00\x00\x00'

Остерегайтесь позволить struct обрабатывать отступы. В С эти структуры:

struct A {       struct B {
    short a;         int a;
    char b;          char b;
};               };

обычно составляют 4 и 8 байтов соответственно. Заполнение происходит в конце структуры в случае, если структуры используются в массиве. Это сохраняет члены 'a' выровненными по правильным границам для структур, которые будут позже в массиве Структурный модуль Python в конце не дополняется:

>>> struct.pack('LB',1,2)
'\x01\x00\x00\x00\x02'
>>> struct.pack('LBLB',1,2,3,4)
'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04'
8 голосов
/ 10 апреля 2010

По умолчанию на многих платформах шорт будет выровнен со смещением, кратным 2, поэтому после символа будет добавлен байт заполнения.

Чтобы отключить это, используйте: struct.unpack("=BH", data),При этом будет использовано стандартное выравнивание, которое не добавляет отступов:

>>> struct.calcsize('=BH')
3

Символ = будет использовать собственный порядок байтов.Вы также можете использовать < или > вместо = для принудительного порядка байтов в младшем или старшем порядке, соответственно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...