为什么此 typedef 给出的 sizeof() 值大于预期?

Why does this typedef give a sizeof() value larger than expected?

我使用这种形式的 typedef 来简化对微处理器寄存器和其中位字段的访问。

  typedef union
  {
     uint8_t        u8Byte;           ///< REG_8 as unsigned byte
     int8_t         i8Byte;           ///< REG_8 as signed byte
     struct
     {
        unsigned b0:1;                ///< Bit 0 of REG_8 type
        unsigned b1:1;                ///< Bit 1 of REG_8 type
        unsigned b2:1;                ///< Bit 2 of REG_8 type
        unsigned b3:1;                ///< Bit 3 of REG_8 type
        unsigned b4:1;                ///< Bit 4 of REG_8 type
        unsigned b5:1;                ///< Bit 5 of REG_8 type
        unsigned b6:1;                ///< Bit 6 of REG_8 type
        unsigned b7:1;                ///< Bit 7 of REG_8 type
     };
  } REG_8;

不幸的是,sizeof(REG_8) returns 2 而不是预期的 1。类似定义 REG_16 和 REG_32 return 大小 2 和 4,正如预期的那样。 sizeof(uint8_t)sizeof(int8_t) return 1,符合预期。

该类型按预期工作。例如,

REG_8  a;
a.u8Byte = 4;

a.b2一个值1,所以不存在对齐问题。

删除 struct 得到 sizeof 值 1,因此看起来存在填充问题,但如果是这样,为什么呢?

谁能解释一下?我正在使用针对 16 位处理器的 Microchip XC16 编译器(基于 GCC)。

可能在您的机器上 sizeof(unsigned)=2,所以任何 "unsigned" 位字段至少占用 2 个字节。用 uint8_t 替换无符号应该使 sizeof(REG_8) 为 1.

另见这个问题: How is the size of a struct with Bit Fields determined/measured?

看来@twin 的想法是正确的,虽然我也找到了另一种解决方案。给出预期 sizeof(REG_8) == 1 的两个备选方案是:

  typedef union
  {
     uint8_t        u8Byte;           ///< REG_8 as unsigned byte
     int8_t         i8Byte;           ///< REG_8 as signed byte
     struct
     {
        unsigned b0:1;                ///< Bit 0 of REG_8 type
        unsigned b1:1;                ///< Bit 1 of REG_8 type
        unsigned b2:1;                ///< Bit 2 of REG_8 type
        unsigned b3:1;                ///< Bit 3 of REG_8 type
        unsigned b4:1;                ///< Bit 4 of REG_8 type
        unsigned b5:1;                ///< Bit 5 of REG_8 type
        unsigned b6:1;                ///< Bit 6 of REG_8 type
        unsigned b7:1;                ///< Bit 7 of REG_8 type
     } __attribute__((packed));
  } REG_8;

...或者...

  typedef union
  {
     uint8_t        u8Byte;           ///< REG_8 as unsigned byte
     int8_t         i8Byte;           ///< REG_8 as signed byte
     struct
     {
        uint8_t b0:1;                ///< Bit 0 of REG_8 type
        uint8_t b1:1;                ///< Bit 1 of REG_8 type
        uint8_t b2:1;                ///< Bit 2 of REG_8 type
        uint8_t b3:1;                ///< Bit 3 of REG_8 type
        uint8_t b4:1;                ///< Bit 4 of REG_8 type
        uint8_t b5:1;                ///< Bit 5 of REG_8 type
        uint8_t b6:1;                ///< Bit 6 of REG_8 type
        uint8_t b7:1;                ///< Bit 7 of REG_8 type
     };
  } REG_8;