views:

80

answers:

4

I've been at this for a while now and it really puzzles me. This is a very distilled code fragment that reproduces the problem:

uint8_t dataz[] = { 1, 2, 3, 4, 5, 6 };

struct mystruct {

    uint8_t dummy1[1];
    uint16_t very_important_data;
    uint8_t dummy2[3];

} *mystruct = (void *) dataz;

printf("%x\n", mystruct -> very_important_data);

What do you expect should be the output ? I'd say x302, but nope. It gives me x403. The same as if using this structure:

struct mystruct {

    uint8_t dummy1[2];
    uint16_t very_important_data;
    uint8_t dummy2[2];

} *mystruct = (void *) dataz;

How would you explain that?

+5  A: 

Packing. The is no guarantee how members of a struct are physically located inside the struct. They may be word-aligned, leaving gaps.

There are pragmas in some versions of C to explictly control packing.

jim mcnamara
+2  A: 

It depends on the compiler, but usually a compiler aligns each member to its natural alignment. In the case you ran into, very_important_data is a uint16_t which probably has a natural alignment of 2 bytes.

MSN
+3  A: 

Most likely, the compiler has added a byte of padding between dummy1 and very_important_data to align very_important_data on a 16-bit boundary.

In general, the alignment and padding of fields in a struct is implementation-dependent, so you shouldn't rely on it. If you absolutely need a particular behavior, many compilers offer #pragma or other directives to control this. Check your compiler's documentation.

Nick Meyer
+5  A: 

As others have mentioned, unless your compiler alignment is byte-aligned, your structure is likely to have "holes" in it. The compiler does this because it speeds up memory access.

If you're using gcc, there is a "packed" attribute which will cause the struct to be byte-aligned, and so remove the "holes":

struct __attribute((__packed__)) mystruct {
    uint8_t dummy1[1];
    uint16_t very_important_data;
    uint8_t dummy2[3];
} *mystruct = (void *) dataz;

However, this will not necessarily fix the problem. The 16-bit value may not be set to what you think it should be, depending on the endianness of your machine. You will have to swap the bytes in any multi-byte integers in the struct. There is no general function to do this, as it would require information on the layout of the structure at run-time, which C does not provide.

Mapping structures to binary data is generally non-portable, even if you get it to work on your machine, right now.

Tim Schaeffer
It doesn't only speed up access - on some platforms, unaligned access raises an exception that terminates your process.
caf