What is VC++ doing when packing bitfields?

前端 未结 5 614
既然无缘
既然无缘 2020-12-03 23:01

To clarify my question, let\'s start off with an example program:

#include 

#pragma pack(push,1)
struct cc {
    unsigned int a   :  3;  
            


        
相关标签:
5条回答
  • 2020-12-03 23:28

    To give another interesting illustrates what's going on, consider the case where you want to pack a structure that crosses a type boundary. E.g.

    struct state {
        unsigned int cost     : 24; 
        unsigned int back     : 21; 
        unsigned int a        :  1; 
        unsigned int b        :  1; 
        unsigned int c        :  1;
    };
    

    This structure can't be packed into 6 bytes using MSVC as far as I know. However, we can get the desired packing effect by breaking up the first two fields:

    struct state_packed {
        unsigned short cost_1   : 16; 
        unsigned char  cost_2   :  8;
        unsigned short back_1   : 16; 
        unsigned char  back_2   :  5;
        unsigned char  a        :  1; 
        unsigned char  b        :  1; 
        unsigned char  c        :  1; 
    };
    

    This can indeed be packed into 6 bytes. However, accessing the original cost field is extremely awkward and ugly. One method is to cast a state_packed pointer to a specialized dummy struct:

    struct state_cost {
        unsigned int cost     : 24;
        unsigned int junk     :  8; 
    };
    
    state_packed    sc;
    state_packed *p_sc = ≻
    
    sc.a = 1;
    (*(struct state_cost *)p_sc).cost = 12345;
    sc.b = 1;
    

    If anyone knows a more elegant way of doing this, I would love to know!

    0 讨论(0)
  • 2020-12-03 23:30

    pst is right. The members are aligned on 1-byte boundaries, (or smaller, since it's a bitfield). The overall structure has size 8, and is aligned on an 8-byte boundary. This complies with both the standard and the pack option. The docs never say there will be no padding at the end.

    0 讨论(0)
  • 2020-12-03 23:31

    MSVC++ always allocates at least a unit of memory that corresponds to the type you used for your bit-field. You used unsigned int, meaning that a unsigned int is allocated initially, and another unsigned int is allocated when the first one is exhausted. There's no way to force MSVC++ to trim the unused portion of the second unsigned int.

    Basically, MSVC++ interprets your unsigned int as a way to express the alignment requirements for the entire structure.

    Use smaller types for your bit-fields (unsigned short and unsigned char) and regroup the bit-fields so that they fill the allocated unit entirely - that way you should be able to pack things as tightly as possible.

    0 讨论(0)
  • 2020-12-03 23:36

    Bitfields are stored in the type that you define. Since you are using unsigned int, and it won't fit in a single unsigned int then the compiler must use a second integer and store the last 24 bits in that last integer.

    0 讨论(0)
  • 2020-12-03 23:45

    Well you are using unsigned int which happens to be 32 Bit in this case. The next boundary (to fit in the bitfield) for unsigned int is 64 Bit => 8 Bytes.

    0 讨论(0)
提交回复
热议问题