Visual C++ эквивалент __attribute__ GCC ((__packed__))

Для некоторых компиляторов есть спецификатор упаковки для структур, например:

Компилятор RealView ARM "__packed"
Компилятор Gnu C имеет "__attribute__ ((__packed__))"
Visual C++ не имеет эквивалента, он имеет только "#pragma pack(1)"

Мне нужно что-то, что я могу вставить в определение структуры.

Любая информация / взломать / предложение? ТИА...

6 ответов

Решение

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

#include "packed.h"
struct Foo { /* members go here */ } PACKED;
#include "endpacked.h"

Тогда для MSVC, упаковано.

#define PACKED
#pragma pack(push,1)

endpacked.h

#pragma pack(pop)
#undef PACKED

Для gcc, упаковано: h:

#define PACKED __attribute__ ((__packed__))

endpacked.h:

#undef PACKED

По сути, упаковка слишком зависит от платформы. Предположим, что ваша упакованная структура содержит 8-битные поля, и рассмотрим некоторую систему с 16-битным байтом. Он не может иметь структуру, представляющую ваши данные просто упаковкой - вам нужно знать, как 8-битные байты преобразуются в 16-битные байты при передаче между двумя системами. Структура на 16-битной машине может нуждаться в битовых полях, и в этом случае вам нужно знать, как их выкладывает реализация.

Так что, если код предназначен для переносимости, вам может потребоваться определить любые упакованные структуры, которые вам нужны, в разделе платформы вашего заголовочного файла. Или, скорее, структурируйте свой код так, чтобы будущий порт мог сделать это, если это необходимо.

Вы можете определить PACK, как это для GNU GCC

#define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__))

и вот так для Visual C++:

#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop) )

И используйте это так:

PACK(
struct myStruct
{
    int a;
    int b;
});

Я знаю, что этот вопрос уже устарел, но я считаю, что есть лучшее решение, чем те, которые были опубликованы ранее. В конце концов, можно поместить прагму в случае MSVC в строку описания структуры. Учтите следующее:

#ifdef _MSC_VER
#  define PACKED_STRUCT(name) \
    __pragma(pack(push, 1)) struct name __pragma(pack(pop))
#elif defined(__GNUC__)
#  define PACKED_STRUCT(name) struct __attribute__((packed)) name
#endif

Тогда это можно использовать так:

typedef PACKED_STRUCT() { short a; int b } my_struct_t;
PACKED_SRUCT(my_other_struct) { short a; int b };

и т.п.

Ключевым моментом здесь является то, что использование __pragma должно быть только вокруг строки объявления структуры. Это должно включать имя структуры, если оно задано, следовательно, имя является параметром макроса. Конечно, это легко распространить на enum / class, который я оставлю читателю в качестве упражнения!

Программа тестирования на странице документации MSDN для пакета полезна для проверки этого.

РЕДАКТИРОВАТЬ

Оказывается, в моем тестировании я использовал компилятор Intel для Windows. При использовании icl.exe этот подход работает без проблем, но с компилятором Microsoft (cl.exe) - нет (протестировано с 2010 и 2013).

Вы можете сделать это наоборот, так как GCC поддерживает прагмы, связанные с пакетом VC++. Смотрите здесь для получения дополнительной информации.

Извлечение...

Для совместимости с компиляторами Microsoft Windows GCC поддерживает набор #pragma директивы, которые изменяют максимальное выравнивание элементов структур (кроме битовых полей нулевой ширины), объединений и классов, определенных впоследствии. Значение n ниже всегда должно быть небольшой степенью двойки и определяет новое выравнивание в байтах.

#pragma pack(n) просто устанавливает новое выравнивание.

#pragma pack() устанавливает выравнивание на тот, который действовал при запуске компиляции (см. также параметр командной строки -fpack-struct[=<n>] см. Параметры кода Gen).

#pragma pack(push[,n]) выталкивает текущую настройку выравнивания во внутренний стек, а затем при необходимости устанавливает новое выравнивание.

#pragma pack(pop) восстанавливает настройку выравнивания до значения, сохраненного в верхней части внутреннего стека (и удаляет эту запись стека).

Обратите внимание, что #pragma pack([n]) не влияет на этот внутренний стек; таким образом можно иметь #pragma pack(push) с последующим множественным #pragma pack(n) экземпляры и завершены одним #pragma pack(pop),

Некоторые цели, например i386 и powerpc, поддерживают ms_struct#pragma который излагает структуру как документально __attribute__((ms_struct)),

#pragma ms_struct on включает макет для объявленных структур.

#pragma ms_struct off отключает макет для объявленных структур.

#pragma ms_struct reset возвращается к макету по умолчанию.

Другое решение, в зависимости от того, какие компиляторы вам нужно поддерживать, состоит в том, чтобы заметить, что GCC поддерживает прагмы упаковки в стиле Microsoft начиная с версии не ниже 4.0.4 (онлайн-документация доступна на gnu.org для версий 3.4.6 и 4.0.4 - Прагмы не описаны в первом, а во втором). Это позволяет вам просто использовать #pragma pack(push,1) до определения структуры и #pragma pack(pop) после определения, и он будет скомпилирован в любом.

Зачем вам что-то идти в структуре?

Я думаю #pragma pack(1) это то же самое, или я что-то упустил?

Вы можете сделать это:

struct Foo
{
#pragma pack(push, 1)
int Bar;
#pragma pack(pop)
};

Но это выглядит некрасиво.

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