c - `*(volatile T*)0x1234;` 能保证翻译成读指令吗?

标签 c volatile

当使用硬件时,有时需要从特定寄存器执行读取并丢弃实际值(例如,清除一些标志)。一种方法是显式读取并丢弃值,例如:

int temp = *(volatile int*)0x1234; // 0x1234 is the register address
(void)temp;                          // To silence the "unused" warning

另一种似乎可行的方法很简单:

*(volatile int*)0x1234;

但这似乎并不明显暗示读取 访问权限,但它似乎转化为我检查过的编译器上的访问权限。标准对此有保证吗?

带有 -O3 的 ARM GCC 示例: https://arm.godbolt.org/z/9Vmt6n

void test(void)
{
    *(volatile int *)0x1234;
}

翻译成

test():
        mov     r3, #4096
        ldr     r3, [r3, #564]
        bx      lr

最佳答案

C 2018 6.7.3 8 说:

An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine, as described in 5.1.2.3.…

由于 *(volatile int*)0x1234; 是一个引用具有 volatile 限定类型的对象的表达式,因此对其求值必须访问该对象。 (当然,这假定 0x1234 代表对 C 实现中某个对象的有效引用。)

根据 C 2018 5.1.2.3 4:

In the abstract machine, all expressions are evaluated as specified by the semantics. An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced (including any caused by calling a function or accessing a volatile object).

根据 C 2018 6.5 1:

An expression is a sequence of operators and operands that specifies computation of a value, or that designates an object or a function, or that generates side effects, or that performs a combination thereof.

因此,表达式指定了值的计算。 5.1.2.3 4 段告诉我们这个评估是由抽象机执行的,6.7.3 8 告诉我们实际实现执行抽象机执行的这个评估。

需要注意的是,“访问”的构成是实现定义的。 C 标准定义的“访问”包括读取和写入(C 3.1 1),但 C 标准无法指定它是指读取或写入某个特定的硬件。

为了进一步探讨语言律师、领域,C 6.3.2.1 2 告诉我们:

Except when it is the operand of the sizeof operator, the unary & operator, the ++ operator, the -- operator, or the left operand of the . operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called lvalue conversion.

因此,由于 *(volatile int*)0x1234; 是一个左值,借助 * 运算符,并且不是列出的运算符的操作数,它转换为存储在对象中的值。因此,此表达式指定了存储在对象中的值的计算。

关于c - `*(volatile T*)0x1234;` 能保证翻译成读指令吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53658582/

相关文章:

c - 何时使用#define 或常量 char/int?

c - C 中的 volatile 和变量修改

c# - C# 中的 volatile 变量赋值

java - 创建可取消线程是否需要 AtomicBoolean?

c - 我在 C 编程中实现 "while loop"时遇到问题

c - 使用循环在 C 中打印模式

c - 使用 fork() 和 execvp() 函数创建 C 程序时遇到问题

C: 声明指向函数的易失指针

c - volatile 和序列点

c - C 中二维变长数组的结构