memory alignment

Started by
13 comments, last by Enigma 15 years, 11 months ago
Hi all few months ago I had one issue (bug) when I was sending data over network. On some rare occasion it seemed that struct that I sent as message body didn't arrived all well. It had ints, chars etc. I resolved that changing struct to BYTE array, memcpy-ing bytes to int and everything was ok. I knew that it must be something with alignment of memory but I didn't know any better way to resolve the problem. Not so long ago I stumbled upon align command. Didn't even know that there is something like that. So easy: __declspec(align(1)) typedef struct and works. Question: What is the right way to align struct where you have several integers, and several bytes? Should I put align(sizeof(int)) or align(1)? Thanks in advance
Advertisement
Data Structure Alignment
The compiler can rearrange and introduce padding in a struct in any way it sees fit. So, it is indeed quite unsafe to send that struct over the network or to a file.
Better than enforcing a specific memory alignment, you can tell the compiler not to shuffle the struct, but let it keep the layout you specified. You can do this by surrounding it with two pragmas:
#pragma pack(push,1)struct MyStruct {   int a;   char b;   long c;};#pragma pack(pop)
Of course, the #pragma solution begins to fall down as soon as you need your code to be compiled on more than one compiler (which may well be never), since #pragma directives are compiler specific and conforming compliers are required to silently ignore ones they don't support.

Be aware of this if multicompiler support is something you currently care about.

A more generalized solution is to implement some kind of serialization mechanism that will serialize instances of class types into a packed byte buffer. There are a number of ways to do this, from library solutions like Boost.Serialize, to writing it manually, to preprocessing and code generation tricks, et cetera.
Thank guys for your replies.

So generally is it safe to:

#pragma pack(push,1)
struct MyStruct {
int a;
char b;
long c;
};
#pragma pack(pop)

if I work only on one compiler?
And if that one compiler is VS, yes. It should be relatively safe.
Quote:Original post by jpetrie
And if that one compiler is VS, yes. It should be relatively safe.


It is [smile]
thanks again
If you are writing structs in binary format directly to files/sockets/etc., get in the habit of adding a compile-time assert to verify that the size is the size you expect.

e.g.:
struct MyStruct {int a;char b;long c;};C_ASSERT(sizeof(MyStruct) == 9);  // or whatever

Then if packing/alignment or other compiler optimizations kick in you'll know about at compile time.

C_ASSERT is a Windows thing. Boost also has BOOST_STATIC_ASSERT.
-Mike
Quote:Original post by Anon Mike
If you are writing structs in binary format directly to files/sockets/etc., get in the habit of adding a compile-time assert to verify that the size is the size you expect.

e.g.:
struct MyStruct {int a;char b;long c;};C_ASSERT(sizeof(MyStruct) == 9);  // or whatever

Then if packing/alignment or other compiler optimizations kick in you'll know about at compile time.

C_ASSERT is a Windows thing. Boost also has BOOST_STATIC_ASSERT.


I have two bytes for crc check. [smile]
Or, if you don't want to clutter your code with pragmas and such, you can fix the problem. Since you didn't say how you are actually receiving the structs, I can't really say what the problem was, except that it sounds strange. Did you send the struct by using sizeof(MyStruct) to get the struct's size? Or did you just sum up the component sizes by hand?

This topic is closed to new replies.

Advertisement