Чтение 32-битных упакованных двоичных данных в 64-битной системе

Я пытаюсь написать расширение 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.

Я знаю, что это глупый вопрос, но каких типов мне нужно остерегаться?

Спасибо.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
0
2 527
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Какой у вас код для чтения двоичных данных? Убедитесь, что вы копируете данные в типы правильного размера, такие как 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-битное целое число.

Когда вы имеете дело с кроссплатформенными проблемами, вам следует остерегаться двух основных вещей:

  1. Битость. Если ваши упакованные данные записаны с 32-битными целыми числами, тогда весь ваш код должен явно указывать 32-битные целые числа при чтении записи и.
  2. Порядок байтов. Если вы переместите свой код с чипов Intel на PPC или SPARC, ваш порядок байтов будет неправильным. Вам нужно будет импортировать свои данные, а затем перевернуть их по байтам, чтобы они соответствовали текущей архитектуре. В противном случае 12 (0x0000000C) будет читаться как 201326592 (0x0C000000).

Надеюсь, это поможет.

Вам нужно убедиться, что вы используете независимые от архитектуры элементы для своей структуры. Например, int может быть 32 бита в одной архитектуре и 64 бита в другой. Как предлагали другие, вместо этого используйте типы стилей int32_t. Если ваша структура содержит невыровненные члены, вам может потребоваться также иметь дело с дополнением, добавленным компилятором.

Еще одна распространенная проблема с данными с кросс-архитектурой - это порядок байтов. Архитектура Intel i386 имеет прямой порядок байтов, но если вы читаете на совершенно другой машине (например, Alpha или Sparc), вам тоже придется об этом побеспокоиться.

Модуль структуры Python обрабатывает обе эти ситуации, используя префикс, переданный как часть строки формата.

  • @ - Использовать собственный размер, порядок байтов и выравнивание. я = sizeof (int), l = sizeof (длинный)
  • = - Использовать собственный порядок байтов, но стандартные размеры и выравнивание (i = 32 бита, l = 64 бита)
  • <- Стандартные размеры / выравнивание с прямым порядком байтов
    • Big-endian standard sizes/alignment

В общем, если данные передаются с вашего компьютера, вы должны привязать порядок байтов и формат размера / заполнения к чему-то конкретному, т. Е. используйте "<" или ">" в качестве формата. Если вы хотите обработать это в своем расширении C, вам может потребоваться добавить код для его обработки.

Другие вопросы по теме