steveo225
steveo225

Reputation: 11882

Force C++ structure to pack tightly

I am attempting to read in a binary file. The problem is that the creator of the file took no time to properly align data structures to their natural boundaries and everything is packed tight. This makes it difficult to read the data using C++ structs.

Is there a way to force a struct to be packed tight?

Example:

struct {
    short a;
    int b;
}

The above structure is 8 bytes: 2 for short a, 2 for padding, 4 for int b. However, on disk, the data is only 6 bytes (not having the 2 bytes of padding for alignment)

Please be aware the actual data structures are thousands of bytes and many fields, including a couple arrays, so I would prefer not to read each field individually.

Upvotes: 63

Views: 95412

Answers (3)

legends2k
legends2k

Reputation: 32904

If you're using GCC, you can do struct __attribute__ ((packed)) { short a; int b; }

On VC++ you can do #pragma pack(1). This option is also supported by GCC.

#pragma pack(push, 1)
struct { short a; int b; };
#pragma pack(pop)

Other compilers may have options to do a tight packing of the structure with no padding.

Upvotes: 84

Heath Raftery
Heath Raftery

Reputation: 4159

A compiler/platform agnostic way to do it is to use byte arrays for the elements, since you need to be explicit about their sizes anyway.

So instead of:

struct __attribute__ ((packed)) {
    short a;
    int b;
}

you can instead use:

struct {
    char a[2];
    char b[4];
}

The alignment requirement of a char is guaranteed to be "the weakest" (in the language of the C11 standard) and is equal to 1. Technically the standard allows extraneous padding to any multiple of this, but I've not seen an implementation that does so. So in practice, this will pack. However YMMV so make sure you check (a static_assert of the sizeof the struct is an excellent safety check).

Of course, you must then also be explicit about conversion to types like short and int. Whether this is a net benefit is left as an exercise to the reader.

Upvotes: -3

John Dibling
John Dibling

Reputation: 101456

You need to use a compiler-specific, non-Standard directive to specify 1-byte packing. Such as under Windows:

#pragma pack (push, 1)

The problem is that the creator of the file took no time to properly byte align the data structures and everything is packed tight.

Actually, the designer did the right thing. Padding is something that the Standard says can be applied, but it doesn't say how much padding should be applied in what cases. The Standard doesn't even say how many bits are in a byte. Even though you might assume that even though these things aren't specified they should still be the same reasonable value on modern machines, that's simply not true. On a 32-bit Windows machine for example the padding might be one thing whereas on the 64-bit version of Windows is might be something else. Maybe it will be the same -- that's not the point. The point is you don't know what the padding will be on different systems.

So by "packing it tight" the developer did the only thing they could -- use some packing that he can be reasonably sure that every system will be able to understand. In that case that commonly-understood packing is to use no padding in structures saved to disk or sent down a wire.

Upvotes: 19

Related Questions