Можно ли разделить структуру C в разделяемой памяти между приложениями, скомпилированными с разными компиляторами?
Я понимаю, что в целом стандарты C и C++ дают авторам компиляторов большую свободу действий. Но, в частности, это гарантирует, что типы POD, такие как члены структуры C, должны быть размещены в памяти в том же порядке, в котором они перечислены в определении структур, и большинство компиляторов предоставляют расширения, позволяющие исправить выравнивание элементов. Таким образом, если у вас был заголовок, который определил структуру и вручную указал выравнивание ее членов, то скомпилировали два приложения с разными компиляторами, используя заголовок, если одно приложение не сможет записать экземпляр структуры в общую память, а другое приложение сможет прочитать его без ошибок?
Однако я предполагаю, что размер содержащихся типов одинаков для двух компиляторов на одной архитектуре (это должна быть уже одна и та же платформа, поскольку мы говорим об общей памяти). Я понимаю, что это не всегда верно для некоторых типов (например, long и long в 64-битных GCC и MSVC), но в настоящее время существуют типы uint16_t, uint32_t и т. Д., А типы float и double определяются стандартами IEEE.
5 ответов
Если вы можете гарантировать одинаковую структуру памяти, включая смещения, а типы данных имеют одинаковый размер между двумя компиляторами, тогда да, это нормально. Потому что в этот момент структура идентична в отношении доступа к данным.
Да, конечно. Я делал это много раз. Проблемы и решения одинаковы, независимо от того, скомпилирован ли и смешан ли смешанный код, или при передаче данных в формате структуры между машинами.
В старые добрые времена это часто происходило при интеграции MS C и почти всего остального: Borland Turbo C. DEC VAX C, Greenhills C.
Самая простая часть - получить количество байтов для различных типов данных для согласования. Например short
на 32-битном компиляторе с одной стороны, так же, как int
на 16-битном компиляторе на другом конце. Поскольку общий исходный код для объявления структур, как правило, полезен, полезен ряд объявлений типа "точка":
typedef signed long s32;
typedef signed short s16;
typedef signed char s8;
typedef unsigned long u32;
typedef unsigned short u16;
typedef unsigned char u8;
...
Microsoft C самая раздражающая. По умолчанию он дополняет элементы до 16-битного выравнивания, а может и больше с 64-битным кодом. Другие компиляторы на x86 не дополняют членов.
struct {
int count;
char type;
char code;
char data [100];
} variable;
Это может показаться смещением code
должен быть следующий байт после type
, но между ними может быть вставлен дополняющий байт. Исправление обычно
#ifdef _MSC_VER // if it's any Microsoft compiler
#pragma pack(1) // byte align structure members--that is, no padding
#endif
Существует также опция командной строки компилятора, чтобы сделать то же самое.
Способ размещения памяти важен в дополнение к размеру типа данных, если вам нужна структура из библиотеки 1, скомпилированная компилятором 1, для использования в библиотеке 2, скомпилированной компилятором 2.
Обратитесь к руководству по вашему компилятору.
большинство компиляторов предоставляют расширения, позволяющие фиксировать выравнивание членов
Вы ограничиваете себя этими компиляторами и взаимно совместимыми #pragma align
стиль? Если так, безопасность продиктована их спецификацией.
В интересах мобильности, вам, возможно, лучше от канав #pragma align
и полагаясь на ваш ABI, который может обеспечить "разумный" стандарт для соответствия всем компиляторам вашей платформы.
Поскольку стандарты C и C++ допускают любую детерминистическую методологию структурирования структуры, они по сути не имеют значения.
Это действительно возможно, вам просто нужно убедиться, что все задействованные компиляторы генерируют одинаковую структуру данных из одного и того же кода. Один из способов проверить это - написать пример программы, которая создает структуру и записывает ее в двоичный файл. Откройте полученные файлы в шестнадцатеричном редакторе и убедитесь, что они совпадают. Кроме того, вы можете привести структуру к массиву uint8_t
и сбросить отдельные байты на экран.
Один из способов убедиться, что размеры данных одинаковы, - это использовать такие типы данных, как int16_t
(из stdint.h) вместо старого int
который может изменять размеры между компиляторами (хотя это редко встречается на двух компиляторах, работающих на одной платформе).
Это не так сложно, как кажется. Существует множество предварительно скомпилированных библиотек, которые можно использовать с несколькими компиляторами. Главное - создать тестовую программу, которая позволит вам убедиться, что оба компилятора одинаково относятся к структуре.