被限制为与volatile相反吗?

问题描述

我可以使用volatile进行以下操作,其中值可以通过外部函数/信号/等来修改:

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

并且编译器/程序集将不会缓存该值。另一方面,使用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,无论函数调用的复杂程度,或持有指向其他变量的指针的任意数量的全局变量。按原样的规则已经要求编译器使asm给出 observable 结果,等效于一次遍历C抽象机1行。 (内存内容不是可观察的结果;这就是为什么在非原子对象上进行数据竞争的行为是不确定的。)


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

volatile说可以在当前作用域之外修改变量

这取决于您的意思。挥发性要强得多,并且可以安全地在当前范围内异步进行修改。

从该作用域调用的函数修改全局exit var 已经很安全了;如果没有内联函数,则编译器通常必须假定每个全局变量都已被修改,对于从全局指针(escape analysis或在此转换单元中调用修改文件的函数可能到达的所有变量)都相同范围的静态变量。

就像我说的,您可以将其用于多线程,但不能。 C11 _Atomic是标准化的,可用于编写可编译到同一asm的代码,但对隐含的确切含义有更多保证。 (特别是订购其他操作。)


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

在C编译器输出中,如果禁用了优化功能,则不会产生任何差异。(多次读取相同的volatile的表达式可能会有细微的差别。)

禁用优化的编译会导致糟糕的无用组件,其中将每个对象都与volatile对待,以实现一致的调试。如Multithreading program stuck in optimized mode but runs normally in -O0所示,通过使变量变为非volatile来实现的优化只能在启用优化的情况下完成。另请参见this Q&A about the same issue on single-core microcontrollers with interrupts

*对于使用这两个关键字的最基本的示例,它将发出汇编指令的示例?

使用gcc10 -O3https://godbolt.org/上尝试一下。您已经有了一个有用的restrict测试用例;它应该让编译器一次加载*c

或者,如果您要进行搜索,那么Ciro Santilli早在2015年就已经分析了您要查询的确切功能,并给出了150多个投票。我是通过搜索site:stackoverflow.com optimize restrict来找到它的,这是第三个匹配项。

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

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...