views:

2357

answers:

4

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...

+3  A: 

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 push(1)
int Bar;
#pragma pop
};

But it looks ugly.

graham.reeds
It is actually #pragma pack(push, 1) and #pragma pack(pop).
Timbo
Yeah it's something like that - I am using VB currently.
graham.reeds
A: 

I do not believe it is possible to specify the packing of individual elements of a struct in Visual Studio. If it where it would be an argument to __declspec. The visual studio documentation lists these as possible __delcspec uses:

  • align(#)
  • allocate("segname")
  • appdomain
  • deprecated
  • dllimport
  • dllexport
  • jitintrinsic
  • naked
  • noalias
  • noinline
  • noreturn
  • nothrow
  • novtable
  • process
  • property({get=get_func_name|,put=put_func_name})
  • restrict
  • selectany
  • thread
  • uuid("ComObjectGUID")

Notably pack is missing.

caspin
+5  A: 

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.

Steve Jessop
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.
Chris Lutz
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.
Steve Jessop
+1  A: 

You can define PACK like this for GNU gcc

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

and like this for Visual C++:

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

And use it like this:

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