Based on what I read about structure alignment, on the other side of a message queue, such a definition may lead to "wrong" reads of messages due to structure alignment carried out by compiler (I use gcc by the way).
Following the guidelines below:
Code:
* Single byte numbers can be aligned at any address
* Two byte numbers should be aligned to a two byte boundary
* Four byte numbers should be aligned to a four byte boundary
* Structures between 1 and 4 bytes of data should be padded so that the total structure is 4 bytes.
* Structures between 5 and 8 bytes of data should be padded so that the total structure is 8 bytes.
* Structures between 9 and 16 bytes of data should be padded so that the total structure is 16 bytes.
* Structures greater than 16 bytes should be padded to 16 byte boundary.
Well for starters, you need to guarantee that things like u_short is indeed 2 bytes long. I don't know what your u_short is, but if it is just an alias on the type unsigned short, it could be 4 bytes long.
An option would be to use the low level C bit fields:
Code:
struct msg
{
//struct in_addr addr1, addr2; // 4-byte
u_int32_t s : 32; //4-byte
u_int32_t a : 32; //4-byte
u_char f : 8; //1-byte
u_int32_t : 8; //1-byte padding //make anonymous, no name
//u_char : 0; //This is equivalent, and tells the compiler to pad to the next alignment. This might be better, as your compiler knows if 4 byte or 8 byte is better. However, you might lose the portability you are looking for.
u_short sp : 16; //2-byte
u_short dp : 16; //2-byte
u_short w : 16; //2-byte
u_int32_t : 64; //8-byte padding //again, anonymous. You might need to use a u_long64_t though.
u_char myArray[1500]; //Cross your fingers this is aligned
u_int32_t : 0; //Final padding. This is always implicit, but might as well write it, for the future.
}
The above method should GUARATEE, things are where they belong, as long as the "receiving" architecture is 8 bits per byte octet architecture (almost guaranteed, unless you are on an embedded platform). If it isn't you are screwed anyways.
I'm not sure if you can use this on the in_addr struct. Probably can, but I'm not sure, and I would not know their size, so I will let you work things out.
If you need more information on this, lookup "C bit field".
Another thing you want to look up, is the more general "C++ binary serialization".
That is all I can help you with, I'm a bit knowledgeable on this stuff, but not that knowledgeable.
Well for starters, you need to guarantee that things like u_short is indeed 2 bytes long. I don't know what your u_short is, but if it is just an alias on the type unsigned short, it could be 4 bytes long.
An option would be to use the low level C bit fields:
Code:
struct msg
{
//struct in_addr addr1, addr2; // 4-byte
u_int32_t s : 32; //4-byte
u_int32_t a : 32; //4-byte
u_char f : 8; //1-byte
u_int32_t : 8; //1-byte padding //make anonymous, no name
//u_char : 0; //This is equivalent, and tells the compiler to pad to the next alignment. This might be better, as your compiler knows if 4 byte or 8 byte is better. However, you might lose the portability you are looking for.
u_short sp : 16; //2-byte
u_short dp : 16; //2-byte
u_short w : 16; //2-byte
u_int32_t : 64; //8-byte padding //again, anonymous. You might need to use a u_long64_t though.
u_char myArray[1500]; //Cross your fingers this is aligned
u_int32_t : 0; //Final padding. This is always implicit, but might as well write it, for the future.
}
The above method should GUARATEE, things are where they belong, as long as the "receiving" architecture is 8 bits per byte octet architecture (almost guaranteed, unless you are on an embedded platform). If it isn't you are screwed anyways.
I'm not sure if you can use this on the in_addr struct. Probably can, but I'm not sure, and I would not know their size, so I will let you work things out.
If you need more information on this, lookup "C bit field".
Another thing you want to look up, is the more general "C++ binary serialization".
That is all I can help you with, I'm a bit knowledgeable on this stuff, but not that knowledgeable.
All the sizes for data types that I listed in my posting have been verified to be correctby using sizeof() statements.
I CAN NOT read the values thSport, thDport and thWin back from myMsg. myMsg->thSport, myMsg->thDport and myMsg->thWin simply lists "meaningless" values instead of 00 50, 11 f7 and 1a 38 respectively.
However, I can read ipSrc (55 11 93 2b), ipDst ( 55 6a 56 5c), thSeq (60 2d 98 ce), thAck ( 6c 8c 10 4f) and thFlags (10) succesfully from myMsg.
To me, this seems to be a structure alignment problem.
Casting pointers to data into structures is always fraught with peril, being so dependant on compiler settings/version/vendor/endianess. The only really safe way is to create serialisation functions to convert known data formats.
"It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
Richard P. Feynman
EDIT: On a side note, you should give up on data alignment and take Paul's (and mine) advice of explicitly serializing the data into a known format.
Nope, that wasn't me this time.
But I agree that it would be better if the data were serialized, instead of taking the cheap, error-prone approach of writing from or reading into a struct, where you are at the mercy of the compiler.
Based on what I read about structure alignment, on the other side of a message queue, such a definition may lead to "wrong" reads of messages due to structure alignment carried out by compiler (I use gcc by the way).
Following the guidelines below:
Code:
* Single byte numbers can be aligned at any address
* Two byte numbers should be aligned to a two byte boundary
* Four byte numbers should be aligned to a four byte boundary
* Structures between 1 and 4 bytes of data should be padded so that the total structure is 4 bytes.
* Structures between 5 and 8 bytes of data should be padded so that the total structure is 8 bytes.
* Structures between 9 and 16 bytes of data should be padded so that the total structure is 16 bytes.
* Structures greater than 16 bytes should be padded to 16 byte boundary.
On x86_64, is the structure definition above correct ?
Am I doing things right ?
Thanks.
The struct is for the purposes of grouping the data together in a logical fashion -- it shouldn't be used as an argument to fwrite(), fread() or whatever function you used to write/read the data. Instead proper serialization should be used.
By proper serialization, you take each member of your struct, and write it to the file in a consistent manner. And on the read, you create an empty structure, and fill it in, one member at a time, with the contents of the file.
Doing a "bulk" write or read of the raw struct is full of danger, even though you see a lot of tutorials showing this being done -- in real practice, don't do it unless you can guarantee you will be using the same compiler, same version of the compiler, same OS, same padding, same compiler options, for the lifetime of your application.
Terribly sorry. I must have been reading another thread you had replied to. I'll be more careful next time. It's no big deal here, but kind of inconsiderate. I'll avoid putting words in your mouth again.
Terribly sorry. I must have been reading another thread you had replied to. I'll be more careful next time. It's no big deal here, but kind of inconsiderate. I'll avoid putting words in your mouth again.
"It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
Richard P. Feynman
Bookmarks