Visual C ++ эквивалент __attribute__ GCC ((__packed__)) - PullRequest
44 голосов
/ 08 октября 2009

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

RealView ARM compiler has "__packed"
Gnu C Compiler has "__attribute__ ((__packed__))"
Visual C++ has no equivalent, it only has the "#pragma pack(1)"

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

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

Ответы [ 6 ]

71 голосов
/ 23 июля 2010

Вы можете определить 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;
});
27 голосов
/ 09 октября 2009

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

#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, упаковано. Ч .:

#define PACKED __attribute__ ((__packed__))

endpacked.h:

#undef PACKED

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

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

15 голосов
/ 29 февраля 2012

Я знаю, что этот вопрос уже устарел, но я считаю, что есть лучшее решение, чем те, которые были опубликованы ранее. В конце концов, можно поместить прагму в случае 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 pack полезна для проверки этого.

EDIT

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

7 голосов
/ 22 декабря 2015

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

Выписка ...

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

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

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

#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 возвращается к макету по умолчанию.

6 голосов
/ 23 июня 2014

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

2 голосов
/ 08 октября 2009

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

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

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

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

Но выглядит ужасно.

...