I originally wrote this question from my tablet and took a lot of shortcuts in doing so that I think ultimately lead to confusion for people who read and/or attempted to answer the question.
I'm not asking for a solution to the problem I originally started with. If you really want the back story read the next paragraph, otherwise skip it.
What brought this up is some old code operating on an array of data of the form {struct, data, struct, data, ...}
, where each data
has arbitrary length. The code accesses each struct through a pointer and when we switched to gcc it began crashing in Solaris due to mis-aligned accesses. One idea for solving this was to alter the type's alignment, as demonstrated below, but I'm probably not going to do that.
The questions to be answered can be summarized as:
- The documentation states alignment cannot be decreased with
aligned
, but I'm able to do it with a typedef. Is it working as intended? - If it's working as intended, why does it require the typedef? Why can't I lower alignment as part of the struct definition?
- note: it can be done with
typedef struct {...}__attribute__((aligned(1))) Typename;
as well
- note: it can be done with
Here's a link to some sample code running on wandbox. In case the link goes dead:
#include <cstdio>
#include <assert.h>
#define ALIGN __attribute__((aligned(1)))
struct Misaligned_1_t { int x; double y; float z; };
struct ALIGN Misaligned_2_t { int x; double y; float z; };
struct Misaligned_3_t { int x; double y; float z; } ALIGN;
// The gcc documentation indicates that the "aligned" attribute
// can only be used to increase alignment, so I was surprised
// to discover this actually works. Why does it work?
typedef Misaligned_1_t ALIGN Aligned_t;
int main( int, char** ) {
char buffer[256];
// The following is meant to simulate a more complicated scenario:
// {SomeStruct, char[arbitrary length], SomeStruct, char[arbitrary length], ...}
// ... where accessing, using and changing each SomeStruct will result in
// misaligned accesses.
auto *m1 = (Misaligned_1_t*)&buffer[1];
auto *m2 = (Misaligned_1_t*)&buffer[1];
auto *m3 = (Misaligned_1_t*)&buffer[1];
auto *a1 = (Aligned_t*)&buffer[1];
// The documentation says we can only reduce alignment with the "packed" attribute,
// but that would change the size/layout of the structs. This is to demonstrate
// that each type is the same size (and should have the same layout).
assert( sizeof(m1) == sizeof(m2)
&& sizeof(m1) == sizeof(m3)
&& sizeof(m1) == sizeof(a1) );
m1->y = 3.14159265358979323846264; // misaligned access
std::printf( "%0.16f\n", m2->y ); // misaligned access
std::printf( "%0.16f\n", m3->y ); // misaligned access
std::printf( "%0.16f\n", a1->y ); // works fine
return 0;
}
I found the answer. I must be blind. From the GCC documentation: