以可变大小字节

时间:2016-09-08 10:22:11

标签: c embedded bit

我想将通用寄存器分成三个独立的寄存器;两个8位寄存器&一个16位寄存器。这是我正在使用的方法,但我认为这可能是错误的。

typedef struct {
       volatile uint8_t reg_0;
       volatile uint8_t reg_1;
       volatile uint16_t reg_2;
} reg_split;

#define REG_BASE (0xA040000C)
#define REG ((reg_split *)REG_BASE)

这就是我访问寄存器的方式:

REG->reg_0 = 0xFF;

这是错误的做法还是更清洁的解决方案?

1 个答案:

答案 0 :(得分:3)

对于所有类型的内存映射,最重要的是验证C代码是否产生预期结果。你必须考虑填充和对齐。

您的例子中有一些小问题:

  • 始终确保代码中的所有十六进制文字都具有合理的类型。在您的情况下,0xA040000C是签名类型,很可能是unsigned int。如果你使用像0x5040000C这样的字面值,它将是(带符号)int类型。在大多数系统上,签名地址没有意义。 “草率类型”可能会导致各种微妙的错误,特别是与各种形式的整数提升相结合时。
  • 将volatile限定符移出结构。如果可能的话,避免在结构体内使用类型限定符 - 它们通常会导致许多类型兼容性打嗝。
  • 硬件寄存器的指针符号有点特殊。最常见的风格是将寄存器视为声明的变量。

考虑到上述评论,您的代码可以重写为:

typedef struct {
  uint8_t  reg_0;
  uint8_t  reg_1;
  uint16_t reg_2;
} reg_split;

#define REG_BASE (0xA040000Cu)
#define REG (*(volatile reg_split *)REG_BASE)

_Static_assert(sizeof(reg_split) == 4, "Unwanted padding detected");

...

REG.reg_0 = 0xFF;