tags:

views:

141

answers:

1

I'm recently working on this platform for which a legacy codebase issues a large number of "cast increases required alignment to N" warnings, where N is the size of the target of the cast.

struct Message
{
   int32_t id;
   int32_t type;
   int8_t  data[16];
};

int32_t GetMessageInt(const Message& m)
{
   return *reinterpret_cast<int32_t*>(&data[0]);
}

Hopefully it's obvious that a "real" implementation would be a bit more complex, but the basic point is that I've got data coming from somewhere, I know that it's aligned (because I need the id and type to be aligned), and yet I get the message that the cast is increasing the alignment, in the example case, to 4.

Now I know that I can suppress the warning with an argument to the compiler, and I know that I can cast the bit inside the parentheses to void* first, but I don't really want to go through every bit of code that needs this sort of manipulation (there's a lot because we load a lot of data off of disk, and that data comes in as char buffers so that we can easily pointer-advance), but can anyone give me any other thoughts on this problem? I mean, to me it seems like such an important and common option that you wouldn't want to warn, and if there is actually the possibility of doing it wrong then suppressing the warning isn't going to help. Finally, can't the compiler know as I do how the object in question is actually aligned in the structure, so it should be able to not worry about the alignment on that particular object unless it got bumped a byte or two?

+2  A: 

One possible alternative might be:

int32_t GetMessageInt(const Message& m)
{
   int32_t value;
   memcpy(&value, &(data[0]), sizeof(int32_t));
   return value;
}

For x86 architecture, the alignment isn't going to matter that much, it's more a performance issue that isn't really relevant for the code you have provided. For other architectures (eg MIPS) misaligned accesses cause CPU exceptions.


OK, here's another alternative:

struct Message
{
    int32_t id;
    int32_t type;
    union
    {
        int8_t  data[16];
        int32_t data_as_int32[16 * sizeof(int8_t) / sizeof(int32_t)];
        // Others as required
    };
};

int32_t GetMessageInt(const Message& m)
{
    return m.data_as_int32[0];
}
spong
Yes- it is a platform that will trigger unaligned read exceptions unless I flag the object as unaligned. I certainly could copy the data but it seems excessive; if I read a file off of disk that fills memory, I want to just say "this is here, this is here, this is here," and not have to be shuffling things around for no actual gain.
dash-tom-bang
@dash-tom-bang: it depends on the compiler, of course, but you might get that `memcpy` for the price of an unaligned (as far as the compiler knows) `int32_t` read. For instance GCC is quite good at this kind of thing, it can optimise variables into registers even if you take an address, provided you don't pass the address to non-inlined code.
Steve Jessop
I don't think the copying would make a huge difference if your compiler has a decent `memcpy` intrinsic.
spong