根据基础类型宽度,位域的行为是否存在差异?

问题描述 投票:0回答:1

我正在定义一些寄存器(它们都是 32 位宽)以使用位域与硬件外设进行交互。起初,我通过混合

uint8_t
uint16_t
uint32_t
类型来定义一切。例如:

... 
// More definitions above
union  {
    volatile uint32_t I2C_REVNB_HI;

    volatile struct {
        uint16_t FUNC   : 12;
        uint8_t RSVD0   : 2;
        uint8_t SCHEME  : 2;
        uint16_t RSVD1  : 16;
    } I2C_REVNB_HI_bits;
}; // 0x04 - 0x08
...
// More definitions below

当位域为

bits <= 8
时,我将其分配给
uint8_t
,同样,当
8 < bits <= 16
时,我将其分配给
uint16_t
并将
16 < bits <= 32
分配给
uint32_t
。然而,这对我来说有点混乱,我将所有内容重构为
uint32_t
,无论位宽如何,因为我认为这并不重要:

... 
// More definitions above
union  {
    volatile uint32_t I2C_REVNB_HI;

    volatile struct {
        uint32_t FUNC    : 12;
        uint32_t RSVD0   : 2;
        uint32_t SCHEME  : 2;
        uint32_t RSVD1   : 16;
    } I2C_REVNB_HI_bits;
}; // 0x04 - 0x08
...
// More definitions below

我尝试使用寄存器定义的两种实现来运行我的代码,但是一切都是

uint32_t
的那个似乎不起作用;外围设备的行为不符合预期。所以我的问题是,这两种实现之间是否有什么不同?我认为不会有什么区别,因为所有位字段的长度与以前相同。我在网上找不到任何关于此的信息。

PS。我正在编写的代码是在AM335X处理器的可编程实时单元之一上运行,以与I2C外设连接,并使用clpru编译器进行编译。

clpru 编译器文档中有关位域 (p108) 的一些注释可能有用,也可能没用:

  • “使用声明的类型处理位字段”
  • “声明为易失性的位字段根据位字段声明的类型进行访问。易失性位字段 引用恰好生成对其存储的一个引用;多个易失性位域访问不是 合并”
  • “包含位域的结构体的大小取决于位域的声明类型。例如, 这两个结构体的大小都是 4 个字节:“
    struct st {int a:4};
    struct st {char a:4; int :22;};

编译器手册(第 69 页):

“除了 _Bool、signed int 和 unsigned int 之外,编译器还允许 char、signed char、unsigned char、 有符号短、无符号长、有符号长、无符号长、有符号长长、无符号长长,以及 枚举类型作为位字段类型。”

更新

我尝试检查是否按照@IanAbbot的建议分配给字段有任何差异:

i2c_refactored.I2C_REVNB_HI = 0;
i2c_refactored.I2C_REVNB_HI_bits.SCHEME = ~0;
i2c_refactored.I2C_REVNB_HI_bits.FUNC   = ~0;
DEBUG_MEMORY_0.status = i2c_refactored.I2C_REVNB_HI;

i2c_original.I2C_REVNB_HI = 0;
i2c_original.I2C_REVNB_HI_bits.SCHEME = ~0;
i2c_original.I2C_REVNB_HI_bits.FUNC   = ~0;
DEBUG_MEMORY_1.status = i2c_original.I2C_REVNB;

但是输出是相同的:

0x0000CFFF
(或
0b00000000000000001100111111111111

c embedded bit-fields texas-instruments peripherals
1个回答
0
投票

C 标准没有指定实现如何在存储单元中布置位字段。 C 2018 6.7.2.1 11 说(添加了强调):

实现可以分配足够大的任何可寻址存储单元来容纳位字段......

因此,C 编译器可以自由地为 2 位位字段分配 1、2 个或更多字节,也可以自由地为 12 位位字段分配两个或更多字节(假设为 8 位字节),等等。它可以根据位字段的标称类型做出决定。

关于标准对选择存储单元施加的唯一约束,也在 6.7.2.1 11 中:

…如果剩余足够的空间,结构中紧随另一个位字段的位字段应被打包到同一单元的相邻位中…

© www.soinside.com 2019 - 2024. All rights reserved.