16 位的位带结构给出的大小为 3 个字节以及不正确的分配

Gri*_*per 1 c memory embedded stm32

我目前正在为 STM32 MCU 编写代码以与外设配合使用,为了更轻松地访问各个位,我使用了位带结构,如下所示:

typedef struct
{
  uint8_t ch3_unreadconv : 1; // 0
  uint8_t ch2_unreadconv : 1; // 1
  uint8_t ch1_unreadconv : 1; // 2
  uint8_t ch0_unreadconv : 1; // 3
  uint8_t not_used_01    : 2; // 4-5
  uint8_t drdy           : 1; // 6
  uint8_t not_used_02    : 2; // 7-8
  uint8_t err_alw        : 1; // 9
  uint8_t err_ahw        : 1; // 10
  uint8_t err_wd         : 1; // 11
  uint8_t not_used_03    : 2; // 12-13
  uint8_t err_chan       : 2; // 14-15
} fdc_status_reg_t;
fdc_status_reg_t statusReg;

// Assign value 13 to the register.
*((uint16_t*) &statusReg) = 0xD;
Run Code Online (Sandbox Code Playgroud)

但当我这样做时,sizeof(statusReg);我得到了3答案。当我使用代码为整个寄存器赋值时,除了最后 2 位(即 )之外,这些位都被正确设置err_chan。我在 GCC 上尝试了相同的方法并得到了类似的结果来测试这是否是 STM 特定问题。经过进一步调查,我发现将第 7 位和第 8 位设置为两个单独的位似乎可以解决问题,即

typedef struct
 {
     uint8_t ch3_unreadconv : 1; // 0
     uint8_t ch2_unreadconv : 1; // 1
     uint8_t ch1_unreadconv : 1; // 2
     uint8_t ch0_unreadconv : 1; // 3
     uint8_t not_used_01    : 2; // 4-5
     uint8_t drdy           : 1; // 6
     uint8_t not_used_02    : 1; // 7
     uint8_t not_used_02_01 : 1; // 8
     uint8_t err_alw        : 1; // 9
     uint8_t err_ahw        : 1; // 10
     uint8_t err_wd         : 1; // 11
     uint8_t not_used_03    : 2; // 12-13
     uint8_t err_chan       : 2; // 14-15
 } fdc_status_reg_t;
Run Code Online (Sandbox Code Playgroud)

sizeof给出2 个字节的正确输出。并且还给出了分配的预测行为。这(对我来说)看起来像是一个填充/内存对齐问题,但我不明白如何,每当在uint8_t第 7 位和第 8 位使用 a 时我就能够重新创建它,但当在uint16_t7-8 位使用 a 时工作正常。请告知可能出现的问题以及可能比在第 7 位分割位更好的解决方法。提前致谢。

ryy*_*ker 5

第一个结构中的字节计数与该字段成员的字节对齐边界相抵触:

uint8_t not_used_02    : 2; // 7-8
Run Code Online (Sandbox Code Playgroud)

这导致该点的位计数为 9,而不是 8,从而调用位字段填充,通过添加一个字节来容纳额外的位,使字节计数达到 3。

如果您可以调整位字段结构中的字段顺序,则可以将字节数减少到 2。或者...

对于位字段,不能保证系统实现在系统之间保持一致,但您可以试验您的实现以获得所需的结果。例如,尝试使用type足够大的值来容纳所有位,例如uint16_t。在我的系统上,对于具有相同字段顺序的相同字段, 使用uint16_t结果为2:sizeof

typedef struct
{
  uint16_t ch3_unreadconv : 1; // 0
  uint16_t ch2_unreadconv : 1; // 1
  uint16_t ch1_unreadconv : 1; // 2
  uint16_t ch0_unreadconv : 1; // 3
  uint16_t not_used_01    : 2; // 4-5
  uint16_t drdy           : 1; // 6
  uint16_t not_used_02    : 2; // 7-8
  uint16_t err_alw        : 1; // 9
  uint16_t err_ahw        : 1; // 10
  uint16_t err_wd         : 1; // 11
  uint16_t not_used_03    : 2; // 12-13
  uint16_t err_chan       : 2; // 14-15
} fdc_status_reg_t;
fdc_status_reg_t statusReg;
Run Code Online (Sandbox Code Playgroud)