在ARM信息中心网站上,他们有this建议使用结构将变量映射到内存地址。
#define PORTBASE 0x40000000
typedef struct Port
{
uint32_t reg0;
uint32_t reg1;
uint32_t reg2;
} Port;
volatile struct Port * const reg_p = (struct Port *)PORTBASE;
但是,我看到其他人建议编译器可以在struct对象的成员之间添加填充,并且确保不会发生这种情况的唯一方法是使用packed属性,如在GCC __attribute__((__packed__))
中,示例
在我看来,填充只会由编译器引入以对齐成员边界,但我没有在C99标准中看到它明确指出这不应该在其他情况下发生。事实上,它似乎表明它可能会发生。
来自C99第6.7.2.1节,
12
结构或联合对象的每个非位字段成员都是对齐的 以适合其类型的实现定义方式。
13
在结构对象中,非位字段成员和其中的单位 位字段驻留的地址按顺序增加 他们被宣布。适当地指向结构对象的指针 转换后,指向其初始成员(或者如果该成员是 位字段,然后到它所在的单元,反之亦然。 结构对象中可能有未命名的填充,但不在其中 开始。
15
结构或联合的末尾可能有未命名的填充。
鉴于上面的例子,是否保证reg1与reg0完全相差32位而不告诉编译器不添加填充?
答案 0 :(得分:1)
添加成员之间的填充,以便将值对齐到32Bit(取决于体系结构) 例如uint32_t应该从对齐的偏移量4 * 2 ^ x开始,以便更快地访问 可以使用普通的32位指针,因为struct只包含32位值 如果PORTBASE是对齐的地址,则自动为真。
因此编译器在这种情况下不应添加填充, 但你可以随时添加
__attribute__((__packed__))
可以肯定。
编译器会在以下情况下添加填充:
struct
{
uint8_t a;
uint32_t b;
}
其中b将以未对齐的地址结束。
问题在于,对于arm而言,您可能会得到与C99不完全兼容的编译器。