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:
aligned
, but I'm able to do it with a typedef. Is it working as intended?typedef struct {...}__attribute__((aligned(1))) Typename;
as wellHere'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:
When used on a struct, or struct member, the aligned attribute can only increase the alignment; in order to decrease it, the packed attribute must be specified as well. When used as part of a typedef, the aligned attribute can both increase and decrease alignment, and specifying the packed attribute generates a warning.