I want to capture some of the data inside some C structures to partially serialize / deserialize them, write bytes from memory to disk, and vice versa.
Structures are not known in advance, they are dynamically built with my own C code generator (as well as code that will serialize it). Serializable fields will be placed at the beginning of the structure.
Let's say a has a structure with 4 fields, and the first two must be serialized:
typedef struct { int8_t x1; int32_t x2; int8_t y1; int32_t y2; } st;
I plan to grab a pointer to a structural variable and write / read bytes n that span the first two fields ( x1, x2 ). I donβt think that I need to worry about alignment / packaging, because I do not intend to serialize in order to survive in different compilations (it is expected that only a unique executable will read / write data). And, since I am targeting a wide range of architecture compilers, I don't want to post assumptions about alignment or compilation settings.
Then I need to count bytes. And I can't just do sizeof(st.x1)+sizeof(st.x2) because of add-on. So, I plan to subtract the pointers, starting from the beginning of the structure to the first "unsaturated" field:
st myst; int partsize = (char*)&myst.y1 - (char*)(&myst); printf("partial size=%d (total size=%d)\n",partsize,sizeof(myst));
It seems to work. And it can be placed in a macro.
(For the record: I tried to write another macro that does not require repeating an instance of the structure, something like this , but here it is not possible - but this is not very important to me).
My question is: is this correct and safe? Can you see a potential trap or some better approach?
Among other things: do C allow standard (and de facto compilers) that the structs fields are in memory in the same order in which they are defined in the source? This is probably a stupid question, but I want to be sure ...
UPDATE: some conclusions from the answers and my own conclusions:
There seems to be no problem with my approach. In particular, C indicates that the structure fields will never change order.
You can also (as was suggested by aswer) calculate from the last constant field and add its size: (char*)&myst.x2 + sizeof(&myst.x2) - (char*)(&myst) . This would be equivalent, except that it would include non-padding bytes (if any) for the last field. A very small advantage - and a very small disadvantage - is to be less simple.
But the accepted answer with offsetof seems to be preferable to my suggestion. This is a clear, expressive and pure compilation time; it does not require an instance of the structure. It also seems standard, available in any compiler. Unless you need a compile-time construct and have an instance of an accessible structure (like my script), both solutions are equivalent.