如果从中断访问标记为
volatile
的结构体成员,是否需要将整个访问链标记为 volatile
?
例如
struct bar
{
volatile uint16_t a;
volatile uint16_t b;
};
struct foo
{
struct bar bar1;
struct bar bar2;
};
struct foo foo_arr[10];
void interrupt_handler(void)
{
struct bar *bar = &foo_arr[0].bar1;
bar->a = 2;
bar->b = 3;
}
会员
a
和b
标记为volatile
就足够了吗?我觉得是这种情况,如果不是,我有一些代码需要修复。
通常,在单个结构体成员而不是结构体对象上指定限定符通常会出现问题。在这种情况下,由于每个成员都是
volatile
,因此您也可以执行 volatile struct bar bar1
,从而允许结构体的非 volatile
实例也存在。
但是,如果
a
和 b
恰好是内存映射的 CPU 寄存器,则不存在它们不是 volatile
的情况,因此通过限定各个成员,可以防止对它们进行任何其他使用在这种特定情况下是一件好事。不过,制作 struct volatile
也没有什么坏处。
对于这些变量的使用,唯一重要的是用于成员对象的“左值访问”的类型,这必须通过正确限定的类型来完成。例如
* (int*)&bar->a
会调用未定义的行为 - 如果您在声明中使用 const
也会发生同样的情况。
编译器也不能对这个结构做出任何假设,它必须始终将其视为
volatile
。然而,如果每次都明确声明 volatile
,那么对于 程序员来说,它会更加清晰和自我记录。当意图将某些东西视为
volatile
时,不声明它 volatile
简直就是糟糕的编程风格。但就 C 语言而言,这是没有必要的。
您可以轻松测试:https://godbolt.org/z/rxqPe8abx 注释掉
volatile
,(x86_64 端口)编译器会将写入优化为单个 32 位写入,这不符合 2 个 volatile
变量。通过 volatile
,我们确实获得了 2 个独立的 16 位写入,这是 C 程序执行规则(“抽象机”)所要求的。