Alignment of bitfields inside unions

∥☆過路亽.° 提交于 2019-12-10 16:49:17

问题


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".


回答1:


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.




回答2:


Well, firstly, __attribute__((__packed__)) is a gcc extension so the standard doesn't have anything to say about what might or might not happen with that.

In general however, the compiler is allowed to insert any padding it feels appropriate between bit fields. In particular, I've seen compilers that given this:

 struct
 {
     short a : 8;
     int b : 8;
 }

will align b on a 32 bit boundary.

Basically, if you use bitfields you're on your own. There's no guarantee of order of the fields or of padding. The only guarantee you have is the size of the bitfield.




回答3:


The question is tagged as C++, but you mention C spec. AFAIK, there is difference between C and C++ in that regard. In C, bitfields can be only of integer type, while C++ allows any integral type.

As bitfields are mapped to integral types, I would expect that the size of a bitfield is always 1, 2 or 4.

Therefore, this would give you sizeof 3:

struct Thing
{
    union
    {
        // without 'short' int would be assumed -> 4 bytes
        unsigned short value:15; // -> maps to short -> 2 bytes
        uint8_t bytes[3];        // -> 3 bytes, so the whole union is 3 bytes long
    };
}

With value:24, it will always be mapped to nearest integral type, i.e. integer.



来源:https://stackoverflow.com/questions/12383708/alignment-of-bitfields-inside-unions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!