gpt4 book ai didi

c - volatile 的语义

转载 作者:太空狗 更新时间:2023-10-29 15:54:12 25 4
gpt4 key购买 nike

为了这个问题,让我们只看对 volatile 变量的读取。我读过的所有讨论,唯一的结论是,对声明为 volatile 的同一个变量的多次读取不能优化为单一效果。

但我认为这有点严格。考虑对一个变量的两次读取,它们之间没有任何副作用,或者它们之间没有读取任何其他 volatile 变量。

现在我们知道 volatile 变量中的值可以随时更改(编译器没有提示)。但是程序员无法确保更改将发生在两次读取之间。这意味着两个读取看到相同的值是程序的有效行为。

那么编译器不能强制执行这种行为吗?进行一次读取并使用该值两次。

例如

int foo(volatile int * x) {
return *x + *x;
}

在这种情况下,编译器可以进行单次读取吗?

我希望我的问题很清楚。

此外,我假设一个读取本身没有副作用的系统(比如计数器的增量,或者值随每次读取而变化)。或者是否存在这样的系统?

我查看了从 gccclang 生成的程序集,即使进行了最大程度的优化,它们也会插入两次读取。我的问题是他们是否过于保守?

编辑:为了不使我的问题复杂化并避免与实现定义的子表达式求值顺序混淆,我们可以看一下示例 -

int foo(volatile int * x) {
int a = *x;
int b = *y;
return a + b;
}

但我还保留了前面的示例,因为一些答案和评论已经引用了它。

最佳答案

从内存位置读取可能会产生副作用。当然,该程序必须使用的不仅仅是标准 C。读取只能在依赖于实现定义行为的程序中产生副作用。

一个常见的例子是读取 memory-mapped peripheral .在许多体系结构中,当数据被读取或写入特定范围的内存位置时,主处理器会与外围设备交换数据。如果内存位置映射到外围设备,则执行两次读取会向外围设备发送两个读取请求。外设可以对每次读取执行非幂等操作。

例如,每次从串行通信外设读取一个字节都会传输外设输入队列中的下一个字节。因此,如果使用该串行外围设备的字节读取寄存器的地址调用 foo,那么它会从外围设备的读取缓冲区中提取两个连续的字节。不允许编译器将行为更改为只读取一个字节。

嗯,除了行为是未定义的,因为读取之间没有序列点,并且从 volatile 读取是一个副作用。正确的功能是

int foo2(volatile int *x) {
int x1 = *x;
int x2 = *x;
return x1 + x2;
}

不过,我希望大多数编译器为 foo 生成与为 foo2 生成相同的代码。

关于c - volatile 的语义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45755642/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com