C语言 无法理解如何gdb内存转储我的结构与位域是正确的给我的结构初始化

ugmeyewa  于 2023-05-22  发布在  其他
关注(0)|答案(1)|浏览(119)

我为自定义网络协议设计了一个Packet结构,如下所示:

typedef struct {
    uint8_t src;
    uint8_t dest;
    uint8_t len;
    uint8_t flag;

    //bitfields allocated R-L? gcc is somehow merging the fields also?
    uint8_t type :4;
    uint16_t seq :12; // 12 bits used for this field.[F3|02] == 0x02F3 on litle endian?
    
    uint8_t checksum;
}Packet;

根据我对位字段和结构填充的理解,每个字段都将存储在连续的字节中(seq将从一个新的字节边界开始)。没有尾随填充,因为我的设备也是x64。
以图形方式:|src|dest|len|flag|type| seq |checksum| 64位头,无结构填充。
为了测试我的数据包以进行进一步的序列化,我通过以下方式初始化了一个数据包:

thispack.src = 0x07;
    thispack.dest = 0x34;
    thispack.len = 0x5F;
    thispack.flag = 0xA2;
    thispack.type = 0x05;
    thispack.seq = 0xAED;
    thispack.checksum= 0x23;

我正在运行一个小字节序系统。我希望结构体的内存布局是:
0x07 0x34 0x5F 0xA2 0x05 0xED 0x0A 0x23,其中seq的字节由little-endian规则反转。
但是,在gdb中运行x/8bx &thispack将返回以下内容:
0x07 0x34 0x5f 0xa2 0xd5 0xae 0x23 0x00
我不明白0xD 5和0xAE是如何获得的。这会导致通过.表示法访问结构体字段时的不确定性:
以下是我认为正确的:

  1. uint8_t mytype = thispack.type应将0x05存储在mytype引用的字节中。
  2. uint16_t myseq = thispack.seq应该将0xED 0x0A存储在分配给myseq的2个字节中。
    我看不出还有什么别的原因。
tf7tbtn2

tf7tbtn21#

好的。在这种情况下,我的设备上的gcc会打包位域吗?
有:

typedef struct {
    uint8_t type :4;
    uint16_t seq :12; // 12 bits used for this field.[F3|02] == 0x02F3 on litle endian?
}Packet;

int main()
{
    printf("%zu\n", sizeof(Packet));
}

结果https://godbolt.org/z/1Teh7Er9f

2

是否有其他原因导致记忆没有按照我预期的顺序排列?
不,你需要使用一个小的变通方法:

typedef struct {
    struct {uint8_t type :4;};
    struct {uint16_t seq :12;}; // 12 bits used for this field.[F3|02] == 0x02F3 on litle endian?
}__attribute__((packed)) Packet;

int main()
{
    printf("%zu\n", sizeof(Packet));
}

结果https://godbolt.org/z/1MGPYsW1W

3

相关问题