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)
};
Но это выглядит некрасиво.