Visual C++ equivalent of GCC's __attribute__ ((__packed__))
Asked Answered
P

6

65

For some compilers, there is a packing specifier for structs, for example ::

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

I need something that I can put into the struct definition.

Any info/hack/suggestion ? TIA...

Printmaking answered 8/10, 2009 at 13:56 Comment(2)
@Caspin: I want to pack the whole struct. @Others: I want to have a #define (in fact 2) to accomplish this for compilers I will use. #pragma trick does not work on some of them.Printmaking
Note that gcc has supported #pragma pack since at least version 4.0; not sure about RealView ARM.Slightly
C
114

You can define PACK like as follows for GNU GCC and MSVC:

#ifdef __GNUC__
#define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__))
#endif

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

And use it like this:

PACK(struct myStruct
{
    int a;
    int b;
});
Craigcraighead answered 22/7, 2010 at 20:0 Comment(4)
This approach was used by Symbian for all such attributes, as they targeted lots of compilers and some wanted the compiler-specific bit written before an identifier, others after etc.Tulatulip
I like this solution, however, it took me a long time to figure out that MSVC++ handles bitfields a little differently than GCC. I was using "int" bitfields of various sizes (1, 7, 8, 16) and discovered that MSVC++ still wanted to pack everything into 4-byte boundaries. By converting over to char for 1,7, and 8 and short for 16 I then got the packing that I was expecting.Retreat
@EricAngell the above works for typedefs if you write PACK(typedef struct { int x; }) MyStruct;. Also you may be able to use #define PACK(...) __VA_ARGS__ __attribute__((__packed__)) etc to handle commas in declaration body.Geophysics
clang-cl doesn't like this construct.Popedom
T
38

I don't know a slick way of doing it, but you could possibly do something horrible like this:

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

Then for MSVC, packed.h:

#define PACKED
#pragma pack(push,1)

endpacked.h

#pragma pack(pop)
#undef PACKED

For gcc, packed.h:

#define PACKED __attribute__ ((__packed__))

endpacked.h:

#undef PACKED

Fundamentally, packing is too platform-dependent. Suppose your packed struct has 8-bit fields in it, and consider some system with a 16-bit byte. It can't have a struct representing your data just by packing - you'd have to know how 8-bit bytes are converted to 16-bit bytes when transferred between the two systems. The struct on the 16bit machine might need bitfields, in which case you'd have to know how the implementation lays them out.

So if the code is intended to be generally portable, you may just have to define whatever packed structures you need in a platform-specific section of your header file. Or rather, structure your code so that a future port can do that if it has to.

Tudor answered 9/10, 2009 at 18:24 Comment(2)
Technically, you could do all of that in one header: #ifndef PACKED / #define PACKED / #else /* !PACKED */ / #undef PACKED / #endif /* PACKED */ and then include the same header twice, once to enable and once to disable. The usefulness / cleanliness / sanity of such a practice is debatable, but so is the practice you suggest.Raid
I think I'll take "begin/end must match", over "must be done an even number of times", thanks ;-). As I said in the answer, in principle you need a platform-specific struct definition. In practice, though, this covers the three compilers the questioner currently cares about, it allows more commonality than just a lot of copy/paste, and it's not spectacularly awful compared with a swarm of #if _WIN32 #elif __GNUC__ and so on around every struct definition. #include is the correct/only way in C to abstract or reuse a code snippet that contains preprocessor directives.Tudor
S
22

I know this question is old now, but I believe there is a better solution than those posted earlier. It is possible to put the pragma in the MSVC case in the struct declaration line after all. Consider the following:

#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

Then this can be used like so:

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

etc.

The key here is that the use of the __pragma only needs to be around the declaration line of the struct. This needs to include the struct name if it is given one, hence the name being a parameter to the macro. Of course, this is easy to extend to enum/class, which I'll leave as an exercise to the reader!

The test program on the pack documentation MSDN page is useful to verify this.

EDIT

It turns out in my testing I was using the Intel Compiler on Windows. Using icl.exe this approach works without a problem, but with the Microsoft compiler (cl.exe), it does not (tested with 2010 and 2013).

Selfdefense answered 29/2, 2012 at 17:46 Comment(3)
I would love it if this actually worked, as it would keep the macro weirdness limited to the opening line of the struct definition, but when I tried this on MSVS 2010 with C++, I got error C2143: syntax error : missing ';' before '{'. I had to revert back to something like Steph's post, where the entire body of the struct definition is the macro argument, which kind of sucks. Especially since it confuses vim context coloring on C files (vim handles it right with C++ files though; I don't know why).Gantrisin
However the PACKED_STRUCT as a keyword is cool. You can combine with Steph's solution like this: #ifdef _MSC_VER # define PACKED_STRUCT( __Declaration__ ) __pragma( pack(push, 1) ) struct __Declaration__ __pragma( pack(pop) ) #elif defined(__GNUC__) # define PACKED_STRUCT( __Declaration__ ) struct __Declaration__ __attribute__((__packed__)) #endif Edited: blocks of code don't render as expected. Sorry.Premeditate
It doesn't work in MSVC. The __pragma(pack(pop)) must be placed after the structure body. Putting it before is not enough.Antebellum
F
16

You can do it the other way round since GCC supports the VC++ pack related pragmas. Look here for more information.

Extract...

For compatibility with Microsoft Windows compilers, GCC supports a set of #pragma directives which change the maximum alignment of members of structures (other than zero-width bitfields), unions, and classes subsequently defined. The n value below always is required to be a small power of two and specifies the new alignment in bytes.

#pragma pack(n) simply sets the new alignment.

#pragma pack() sets the alignment to the one that was in effect when compilation started (see also command line option -fpack-struct[=<n>] see Code Gen Options).

#pragma pack(push[,n]) pushes the current alignment setting on an internal stack and then optionally sets the new alignment.

#pragma pack(pop) restores the alignment setting to the one saved at the top of the internal stack (and removes that stack entry).

Note that #pragma pack([n]) does not influence this internal stack; thus it is possible to have #pragma pack(push) followed by multiple #pragma pack(n) instances and finalized by a single #pragma pack(pop).

Some targets, e.g. i386 and powerpc, support the ms_struct #pragma which lays out a structure as the documented __attribute__((ms_struct)).

#pragma ms_struct on turns on the layout for structures declared.

#pragma ms_struct off turns off the layout for structures declared.

#pragma ms_struct reset goes back to the default layout.

Following answered 22/12, 2015 at 5:53 Comment(0)
S
6

Another solution, depending what compilers you need to support, is to notice that GCC has supported the Microsoft-style packing pragmas since at least version 4.0.4 (the online documentation is available at gnu.org for versions 3.4.6 and 4.0.4 - the pragmas are not described in the former and are in the latter). This lets you just use #pragma pack(push,1) before a structure definition and #pragma pack(pop) after the definition and it will compile in either.

Slightly answered 23/6, 2014 at 1:47 Comment(1)
Confirmed to work, but IMHO @Steph's solution is much more elegant than putting pairs of #pragma before and after each declaration.Premeditate
I
4

Why do you need something to go in the struct?

I think #pragma pack(1) is the same, or am I missing something?

You can do this:

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

But it looks ugly.

Incarnadine answered 8/10, 2009 at 14:3 Comment(1)
It is actually #pragma pack(push, 1) and #pragma pack(pop).Symphonious

© 2022 - 2024 — McMap. All rights reserved.