Я пытаюсь написать расширение Python C, которое считывает упакованные двоичные данные (они хранятся как структуры структур), а затем анализирует их на объекты Python. Все работает должным образом на 32-битной машине (двоичные файлы всегда записываются на 32-битной архитектуре), но не на 64-битной машине. Есть ли «предпочтительный» способ сделать это?
Было бы много кода для публикации, но в качестве примера:
struct
{
WORD version;
BOOL upgrade;
time_t time1;
time_t time2;
} apparms;
File *fp;
fp = fopen(filePath, "r+b");
fread(&apparms, sizeof(apparms), 1, fp);
return Py_BuildValue("{s:i,s:l,s:l}",
"sysVersion",apparms.version,
"powerFailTime", apparms.time1,
"normKitExpDate", apparms.time2
);
Теперь в 32-битной системе это отлично работает, но на 64-битной мои размеры time_t разные (32-битные и 64-битные длинные).
Блин, вы люди быстрые.
Патрик, я изначально начал использовать пакет struct, но обнаружил, что он тормозит для моих нужд. К тому же я искал повод написать расширение Python.
Я знаю, что это глупый вопрос, но каких типов мне нужно остерегаться?
Спасибо.






Какой у вас код для чтения двоичных данных? Убедитесь, что вы копируете данные в типы правильного размера, такие как int32_t, а не только в int.
Почему вы не используете пакет структура?
Модуль 'struct' должен уметь это делать, хотя выравнивание структур в середине данных всегда является проблемой. Однако сделать это не очень сложно: выясните (один раз), по какой границе выровнены структуры-в-структурах, затем проложите (вручную, с помощью спецификатора 'x') к этой границе. Вы можете дважды проверить заполнение, сравнив struct.calcsize () с вашими фактическими данными. Это, конечно, проще, чем писать для него расширение C.
Чтобы продолжать использовать Py_BuildValue () таким образом, у вас есть два варианта. Вы можете определить размер time_t во время компиляции (с точки зрения фундаментальных типов, например, int, a long или ssize_t), а затем использовать правильный символ формата для Py_BuildValue - 'i' для int, 'l' для длинного, 'n' для ssize_t. Или вы можете использовать PyInt_FromSsize_t () вручную, и в этом случае компилятор выполняет преобразование за вас, а затем использует символы формата «O» для передачи результата в Py_BuildValue.
Явно укажите, что ваши типы данных (например, целые числа) 32-битные. В противном случае, если у вас есть два целых числа рядом друг с другом, когда вы их читаете, они будут прочитаны как одно 64-битное целое число.
Когда вы имеете дело с кроссплатформенными проблемами, вам следует остерегаться двух основных вещей:
0x0000000C) будет читаться как 201326592 (0x0C000000).Надеюсь, это поможет.
Вам нужно убедиться, что вы используете независимые от архитектуры элементы для своей структуры. Например, int может быть 32 бита в одной архитектуре и 64 бита в другой. Как предлагали другие, вместо этого используйте типы стилей int32_t. Если ваша структура содержит невыровненные члены, вам может потребоваться также иметь дело с дополнением, добавленным компилятором.
Еще одна распространенная проблема с данными с кросс-архитектурой - это порядок байтов. Архитектура Intel i386 имеет прямой порядок байтов, но если вы читаете на совершенно другой машине (например, Alpha или Sparc), вам тоже придется об этом побеспокоиться.
Модуль структуры Python обрабатывает обе эти ситуации, используя префикс, переданный как часть строки формата.
- Big-endian standard sizes/alignment
В общем, если данные передаются с вашего компьютера, вы должны привязать порядок байтов и формат размера / заполнения к чему-то конкретному, т. Е. используйте "<" или ">" в качестве формата. Если вы хотите обработать это в своем расширении C, вам может потребоваться добавить код для его обработки.