I'm a bit puzzled by how the following code gets layed out in memory:
struct Thing
{
union
{
unsigned value:24;
uint8_t bytes[3];
};
Thing(int v)
:value(v)
{}
void foo()
{
printf("Thing %p value=%d !\n", this, value);
}
} __attribute__((__packed__));
On gcc 3.3, 4.3 or 4.6 on Linux (without any special options I can think of - only "-Wall -g" on 4.6), the size of the structure is always 4:
$ pahole ./union
struct Thing {
union {
unsigned int value; /* 4 */
unsigned char bytes[3]; /* 3 */
};
[...]
We had some similar code here where we had the unsigned value:24 in a structure, and somebody added the union and inadvertently increased the size of the struct from 3 to 4 bytes. The same thing happens if I try to define the union as "packed" - size is still 4. Is this behavior as per the C++ spec? What would be the explanation?
later edit: replaced "C spec" with "C++ spec".
You missed the packed attributes to your anonymous union. Consider this example:
#define PACKED __attribute__((__packed__))
struct S1 { unsigned value:24; } PACKED ;
struct S2 { union { char a[3]; unsigned value:24; }; } PACKED ;
struct S3 { union { char a[3]; unsigned value:24; } PACKED ; };
int main() {
std::cout << sizeof(S1) << std::endl;
std::cout << sizeof(S2) << std::endl;
std::cout << sizeof(S3) << std::endl;
}
Output:
3
4
3
The packed attribute is a little weird, I always try and test every possible combination to get proper result.