Как получить одинаковую структуру в заголовочном файле для 32- и 64-битных машин? - PullRequest
1 голос
/ 22 февраля 2012

У меня есть структура, которая должна иметь одинаковую форму (по крайней мере, такого же размера, я думаю, что смещения придут с ней) для 32- и 64-битных машин.

Наша структура представляет собой запутанный тип, размер генерируется во время сборки, и мы не можем знать, будет ли этот тип использоваться в 32-битной или 64-битной арке.

Что лучшепрактиковаться, чтобы сделать это?У вас есть указания по проекту?

Ответы [ 2 ]

0 голосов
/ 22 февраля 2012

У меня есть структура, которая должна иметь одинаковую форму (по крайней мере, такого же размера, я думаю, что смещения придут с ней) для 32- и 64-битных машин.

Технически возможно, но не используется на практике.

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

Стандартный способ решения этой проблемы - использовать один и тот же заголовочный файл для 32- и 64-битных платформ. и имеют две сборки вашей библиотеки. 32-битный клиент вашего заголовка связывается с 32-битной библиотекой, то же самое относится и к 64.

Если в конечном итоге объект 32-битной структуры должен попасть в 64-битный код (или наоборот), то должен быть фрагмент кода, который выполняет преобразование. Вот как 32-битный glibc работает на 64-битном ядре.

Простой медленный способ преобразования заключается в сериализации в тексте и десериализации обратно.

0 голосов
/ 22 февраля 2012

Если я правильно понимаю, вы хотите сгенерировать структуру, которая должна иметь точно такую ​​же структуру в 32-разрядной системе, что и в 64-разрядной системе.

например. предположим, что вы сгенерируете эту структуру:

struct S
   {
   long l;
   char *s;
   int i;
   long l2;
   };

Тогда в 64-битном варианте это будет другой макет, чем в 32-битном (в этом случае char-указатель будет иметь другой размер). Если вы скомпилируете это на старой системе DOS, тогда int будет 16-битным, а не 32-битным, и у вас снова будет другой макет.

Лучший способ справиться с этим - определить свои собственные типы и использовать их в своей структуре, например:

typedef long  MY_INT4;
typedef short MY_INT2;

Затем используйте эти типы в своей структуре. Если вам когда-либо понадобится портировать на другую систему, вам нужно только просмотреть ваши typedefs.

struct S
   {
   MY_INT4 m1;
   MY_INT2 m2;
   };

Для некоторых типов (например, для указателей) этот прием не работает, поскольку нет встроенного типа для 32-разрядных или для 64-разрядных указателей, все указатели одинаковы (если мы забываем о старой DOS-версии). - и ближние указатели).

Для этих типов вы можете использовать макросы. Например. это:

struct S
   {
   MY_INT4 m1;
   MY_INT2 m2;
   MY_POINTER(char,m3);
   };

Тогда для 64-битных систем вам нужно только определить MY_POINTER следующим образом:

#define MY_POINTER(t,m) t *m

Для 32-битных систем вы можете определить это так:

#define MY_POINTER(t,m) t *m; t *dummy

Таким образом, для 32-битных систем мы добавляем 2 поля указателя вместо 1.

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

Вы можете решить эту проблему с помощью безымянного объединения. Определите свой макрос следующим образом:

#define MY_POINTER(t,m) t *m; union {t *dummy;}

Обратите внимание, что с этим решением я проигнорировал проблему упорядочения байтов. Если вы хотите решить это, вам нужно погрузиться глубже.

...