简体   繁体   English

具有位域大小的结构

[英]Structure with bit-fields size

I tried to use a structure with different sized bit-fields.我尝试使用具有不同大小位域的结构。 The total number of bits used is 64. However, when I check the structure size, I get 11 instead of an expected 8 .使用的总位数是 64。但是,当我检查结构大小时,我得到11而不是预期的8 By trying to decompose the structure, I saw the difference came from the day field.通过尝试分解结构,我看到差异来自于场。 If I pack every bit to get 8-bits packs, the day field is packed beetween the "end" of month and the "start" of hour .如果我打包每一位以获得 8 位包,那么day字段会在的“结束”和小时的“开始”之间打包。 I don't know if this is a good approach.我不知道这是否是一个好方法。 Can someone explain me that ?有人可以解释我吗?

typedef unsigned char uint8_t;

typedef struct frameHeader_t
    {
        uint8_t encryption       : 2;
        uint8_t frameVersion     : 2;
        uint8_t probeType        : 4;
        uint8_t dataType         : 5;
        uint8_t measurePeriod    : 3;
        uint8_t remontePerdiod   : 4;
        uint8_t nbrMeasure       : 2;
        uint8_t year             : 7;
        uint8_t month            : 4;
        uint8_t day              : 5;
        uint8_t hour             : 5;
        uint8_t minute           : 6;
        uint8_t second           : 6;
        uint8_t randomization    : 5;
        uint8_t status           : 4;

    }FrameHeader;

int main()
{

    FrameHeader my_frameHeader;
    printf("%d\n", sizeof(FrameHeader));
    return 0;
}

If you run it through the pahole tool, you should get an explanation:如果你通过pahole工具运行它,你应该得到一个解释:

struct frameHeader_t {
    uint8_t                    encryption:2;         /*     0: 6  1 */
    uint8_t                    frameVersion:2;       /*     0: 4  1 */
    uint8_t                    probeType:4;          /*     0: 0  1 */
    uint8_t                    dataType:5;           /*     1: 3  1 */
    uint8_t                    measurePeriod:3;      /*     1: 0  1 */
    uint8_t                    remontePerdiod:4;     /*     2: 4  1 */
    uint8_t                    nbrMeasure:2;         /*     2: 2  1 */

    /* XXX 2 bits hole, try to pack */

    uint8_t                    year:7;               /*     3: 1  1 */

    /* XXX 1 bit hole, try to pack */

    uint8_t                    month:4;              /*     4: 4  1 */

    /* XXX 4 bits hole, try to pack */

    uint8_t                    day:5;                /*     5: 3  1 */

    /* XXX 3 bits hole, try to pack */

    uint8_t                    hour:5;               /*     6: 3  1 */

    /* XXX 3 bits hole, try to pack */

    uint8_t                    minute:6;             /*     7: 2  1 */

    /* XXX 2 bits hole, try to pack */

    uint8_t                    second:6;             /*     8: 2  1 */

    /* XXX 2 bits hole, try to pack */

    uint8_t                    randomization:5;      /*     9: 3  1 */

    /* XXX 3 bits hole, try to pack */

    uint8_t                    status:4;             /*    10: 4  1 */

    /* size: 11, cachelines: 1, members: 15 */
    /* bit holes: 8, sum bit holes: 20 bits */
    /* bit_padding: 4 bits */
    /* last cacheline: 11 bytes */
};

You're using uint8_t as the base type so the fields are getting padded to groups of 8 bits.您使用uint8_t作为基本类型,因此字段被填充为 8 位组。

You should be able to completely eliminate the padding, somewhat more portably than with __attribute((packed)) by using unsigned long long / uint_least64_t (at least 64 bits large) as the base type of the bitfields, but technically the non-int/non-unsigned-int base types for bitfields aren't guaranteed to be supported, but you could use unsigned (at least 16 bits guaranteed by the C standard) after reorganizing the bitfields a little, for example into:通过使用unsigned long long / uint_least64_t (至少 64 位大)作为位域的基本类型,您应该能够完全消除填充,比使用__attribute((packed))__attribute((packed)) ,但从技术上讲,非 int/不保证支持位域的 non-unsigned-int 基类型,但您可以在稍微重新组织位域后使用unsigned (C 标准保证至少 16 位),例如:

typedef struct frameHeader_t
{
    //16
    unsigned year             : 7;
    unsigned randomization    : 5;
    unsigned month            : 4;

    //16
    unsigned second           : 6;
    unsigned minute           : 6;
    unsigned status           : 4;

    //16
    unsigned hour             : 5;
    unsigned dataType         : 5;
    unsigned probeType        : 4;
    unsigned encryption       : 2;

    //16
    unsigned day              : 5;
    unsigned remontePerdiod   : 4;
    unsigned measurePeriod    : 3;
    unsigned nbrMeasure       : 2;
    unsigned frameVersion     : 2;

}FrameHeader; 
//should be an unpadded 8 bytes as long as `unsigned` is 16,
//32, or 64 bits wide (I don't know of a platform where it isn't)

(The padding or lack thereof isn't guaranteed, but I've never seen an implementation insert it unless it was necessary.) (不能保证填充或缺少填充,但我从未见过实现插入它,除非有必要。)

to avoid the packing magic I usually use fixed size unsigned types with the same size为了避免打包魔术,我通常使用相同大小的固定大小的无符号类型

typedef struct frameHeader_t
    {
        uint64_t encryption       : 2;
        uint64_t frameVersion     : 2;
        uint64_t probeType        : 4;
        uint64_t dataType         : 5;
        uint64_t measurePeriod    : 3;
        uint64_t remontePerdiod   : 4;
        uint64_t nbrMeasure       : 2;
        uint64_t year             : 7;
        uint64_t month            : 4;
        uint64_t day              : 5;
        uint64_t hour             : 5;
        uint64_t minute           : 6;
        uint64_t second           : 6;
        uint64_t randomization    : 5;
        uint64_t status           : 4;

    }FrameHeader;

https://godbolt.org/z/BX2QsC https://godbolt.org/z/BX2QsC

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM