restricted 是 volatile 的对立面吗?

Is restricted the opposite of volatile?

我可以将 volatile 用于以下内容,其中值可能会被外部 function/signal/etc 修改:

volatile int exit = 0;
while (!exit)
{
    /* something */
}

而 compiler/assembly 不会缓存该值。另一方面,使用 restrict 关键字,我可以告诉编译器变量没有别名/在当前范围内仅被引用一次,编译器可以尝试优化它:

void update_res (int *a , int *b, int * restrict c ) {
    * a += * c;
    * b += * c;
}

这两者基本是对立的,这样理解对吗? volatile 说变量可以在当前作用域外修改而 restrict 说不能?对于使用这两个关键字的最基本示例,它将发出的汇编指令示例是什么?

它们并不完全相反。但是,是的,volatile 给优化器一个硬约束 而不是 优化对对象的访问,而 restrict 是对优化器关于别名的承诺/保证,因此从广义上讲,它们在优化器的自由度方面作用相反。 (当然,通常只在优化构建中很重要。)

restrict 完全是可选的,只允许额外的性能。 volatile sig_atomic_t 对于信号处理程序和主程序或设备驱动程序之间的通信可能是“需要的”。对于任何其他用途,_Atomic 通常是更好的选择。除此之外,正常代码的正确性也不需要 volatile 。 (_Atomic 具有类似的效果,尤其是对于当前故意不优化原子的编译器。)volatile_Atomic 都不需要 single-threaded 没有信号处理程序的代码的正确性,无论这一系列函数调用有多复杂,或者有多少全局变量持有指向其他变量的指针。 as-if 规则已经要求编译器使 asm 给出 observable 结果等同于一次单步执行 C 抽象机 1 行。 (内存内容不是可观察的结果;这就是为什么 non-atomic 对象上的数据竞争是未定义的行为。)


volatile 意味着每个 C 变量读取(左值到右值的转换)和写入(赋值)都必须成为 asm 加载和存储。在实践中是的,这意味着它对于异步更改的内容是安全的,例如 MMIO 设备地址,或者作为使用 memory_order_relaxed 滚动您自己的 _Atomic int 的糟糕方法。 (When to use volatile with multi threading? - 基本上从不在 C11 / C++11 中。)

volatile says the variable can be modified outside the current scope

这取决于你的意思。 Volatile 比它强得多,并且可以安全地在当前范围内异步修改它。

从该范围调用的函数修改全局 exit var 已经是安全的;如果一个函数没有被内联,编译器通常必须假设每个全局变量都可以被修改,对于所有可能从全局指针(escape analysis)或从调用这个翻译单元中修改file-scoped静态变量。

正如我所说,您可以将它用于 multi-threading,但不要这样做。 C11 _Atomic 是标准化的,可用于编写编译为相同 asm 的代码,但对隐含的内容和未隐含的内容有更多保证。 (特别是订购其他操作。)


它们在 hand-written asm 中没有等效项,因为源代码和机器代码 asm 之间没有优化器。

在 C 编译器输出中,如果您在禁用优化的情况下进行编译,您将不会注意到差异。(嗯,在读取相同 volatile 多次。)

在禁用优化的情况下进行编译会使 asm 变得糟糕而无趣,其中 每个 对象的处理方式与 volatile 非常相似,以启用一致的调试。作为 shows, the optimizations allowed by making variables plain non-volatile only get done with optimization enabled. See also this Q&A about the same issue on single-core microcontrollers with interrupts.

  • Why does clang produce inefficient asm with -O0 (for this simple floating point sum)?
  • - 很确定我已经多次链接你了。

*What would be an example of the assembly instructions it would emit for the most basic example using these two keywords?

https://godbolt.org/ 上使用 gcc10 -O3 亲自尝试一下。您已经有一个有用的 test-case for restrict;它应该让编译器加载 *c 一次。

或者,如果您进行搜索,Ciro Santilli 已经在 2015 年分析了您所询问的确切功能,并给出了超过 150 个赞成票的答案。我通过搜索 site:whosebug.com optimize restrict 找到了它,这是第 3 次点击。

Realistic usage of the C99 'restrict' keyword? 显示你的确切情况,包括 asm 输出 with/without 限制,以及对该 asm 的分析/讨论。