2014-01-24 5 views
6

Я только что попытался использовать struct.pack в Python в первый раз, и я не понимаю его поведение, когда я смешиваю типыПочему типы микширования в Python struct.pack используют больше пространства, чем необходимо?

Когда я пытаюсь упаковать один символ и ничего больше, он работает как ожидается, т.е.

struct.pack("b",1) 

дает '\x01'. Но как только я пытаюсь смешивать данные другого типа, символ заполняется так долго, как этот тип, например.

struct.pack("bi",1,1) 

дает '\x01\x00\x00\x00\x01\x00\x00\x00'.

Является ли это стандартным поведением и почему? Есть ли способ обойти это?

Редактировать

Проще говоря:

>>> struct.calcsize("b") 
1 
>>> struct.calcsize("i") 
4 
>>> struct.calcsize("bi") 
8 
+2

И удивительно: 'struct.calcsize ('d')' → 8, 'struct.calcsize ('bd')' → 16. Выравнивание и отступы, похоже, зависят от других типов. Это не интуитивно, даже если вы ожидаете выравнивания. EDIT: Я вижу, что размер '' d''равен 8, и определяет, где он может начинаться (с кратным 8), следовательно, отступы. – Alfe

+2

@Alfe Именно поэтому 'struct.calcsize ('db')' равно 9 (обратите внимание, что в C обычно будет 12, поскольку слова должны быть заполнены полностью). – poke

+0

Да, @poke, приятное понятие обмениваться двумя элементами, чтобы показать, что отступ не относится к байту, а к двойнику. – Alfe

ответ

8

struct.pack обычно используется для доступа к структурам памяти, а не файлам. В памяти доступ к данным, который занимает несколько байтов на нечетном/неравномерном адресе, может привести к исключениям или потерям производительности.

Именно поэтому компиляторы выравнивают данные (обычно на границе 4 или 8 байт) и the struct module в Python делают то же самое.

Чтобы отключить это, вы можете использовать первый символ строки формата, чтобы задать порядок и порядок байтов. В вашем случае попробуйте struct.pack("=bi",1,1)

Если вы ничего не укажете, то неявный @, что означает «собственный порядок, размер и выравнивание байта». See the documentation for other options.

4

Yes, it is.

По умолчанию, типы C представлены в родном формате и порядке байт машины, и правильно выровнены, пропуская pad байты, если необходимо (в соответствии с правилами, используемыми компилятором C).

Если вы не хотите, выравнивание, просто указать порядок байтов, начиная свой формат строки с '=', '<' или '>' (такой же, как '!').

2

От manual:

По умолчанию результата упаковки данного C-структуры включает в себя площадку байт для того, чтобы поддерживать правильное выравнивание для типов C, участвующих; Аналогично, выравнивание учитывается при распаковке. Это поведение выбирается так, чтобы байты упакованной структуры точно соответствовали макету в памяти соответствующей структуры C.

i представляет собой 4-байтовое целое число, которое будет помещено на своем собственном слова. Таким образом, что-нибудь рядом с ним, которое не заполняет слово, будет дополнено, чтобы сделать это. Вы можете переопределить это поведение, указав byte order без собственного выравнивания.

Вот почему - с более сложными структурами - упорядочение вещей внутри вещей много.

См. Также Wikipedia article по теме.

2

См. the documentation for struct; в частности, он говорит:

По умолчанию результат упаковки данной C-структуры включает в себя байты с байтами, чтобы поддерживать правильное выравнивание для задействованных типов C; Аналогично, выравнивание учитывается при распаковке. Это поведение выбирается так, чтобы байты упакованной структуры точно соответствовали макету в памяти соответствующей структуры C.

И см., Например, этот вопрос переполнения стека для макета памяти C struct: C struct memory layout?

Короче говоря, целое число составляет 4 байта и поэтому оно должно начинаться с кратного 4. Если вы измените порядок b и i вокруг, проблема не должна возникают.

 Смежные вопросы

  • Нет связанных вопросов^_^