我有一个表示一组硬件寄存器的结构。这里有些部分是保留的,既不能写也不能读。是否有占位符或类似的东西,而不是使用明显的变量命名?
typedef volatile struct RegisterStruct
{
uint8 BDH;
uint8 BDL;
...
uint8 IR;
uint8 RESERVED0; // this area should not be accessed
...
}
答案 0 :(得分:3)
明显的命名是正确的选择,因为C中没有“保留”功能。
您可以使用字节大小的整数数组正确填充到正确的长度:
typedef volatile struct RegisterStruct
{
uint8_t BDH;
uint8_t BDL;
uint8_t IR;
uint8_t __RESERVED[num_of_reserved_bytes]; // this area should not be accessed
uint8_t NEXT_REGISTER_NAME;
};
答案 1 :(得分:2)
通常使用结构体进行寄存器映射(或类似地,对于数据通信协议映射)的问题是结构可能在任何地方都包含填充字节。
如果您为此目的使用结构(或联合),则必须通过添加一行来确保禁用填充,例如
_Static_assert(sizeof(RegisterStruct) == sizeof(uint8_t)*4, "Padding detected");
这样可以防止填充错误,因为它会阻塞带有填充的结构。
不幸的是,你不能以可移植的方式禁用struct padding;大多数情况下,你不想要禁用它,因为它会使程序运行速度最慢,在最坏的情况下,你会得到未对齐访问的硬件异常,所有这些都取决于CPU。
禁用填充的最常见非标准扩展名是#pragma pack(1)
,但它是非标准且不可移植的。
在我看来,避免所有这些问题的最好方法是完全避免结构用于实际映射。相反,只需将所有内容声明为普通的volatile变量。 (或者通过使用宏,遗憾的是,您可以将某些内容映射到标准C中的特定内存位置)。
当你走得那么远时,没有必要使用任何“保留”的占位符。只是不要将任何内容映射到那些保留的内存位置。
实际上,为什么你想在结构中拥有许多硬件寄存器实际上没有合理的理由,即使由于某些原因在嵌入式编译器中这样做很受欢迎。你会发现为这些编译器编写的寄存器映射是不可读的,而且非常不标准。
对于通信协议,使结构更有意义,但是通常会编写序列化/反序列化例程来填充结构。
答案 2 :(得分:1)
C中没有任何东西可以在结构中声明一个没有名称的占位符/空洞或者名称不可读的东西(const可以帮助但只有写保护)。而且我在gcc的扩展中看不到任何可以帮助的内容。
但是你可以通过使用预处理器来加扰名称,例如:
#define GLUE(X,Y,Z) X ## Y ## Z
#ifdef __GNUC__
#define SCRAMBLE(X) GLUE(X,_,__COUNTER__)
#else
#define SCRAMBLE(X) GLUE(X,_,__LINE__)
#endif
typedef volatile struct
{
uint8 BDH;
uint8 BDL;
// ...
uint8 IR;
uint8 SCRAMBLE(RESERVED0);
// ...
} RegisterStruct;