为什么在C语言中需要使用volatile?

551

为什么在C语言中需要使用volatile?它有什么用途?它会做什么?


2
https://dev59.com/8XVD5IYBdhLWcg3wJIAK - Frederik Slijkerman
相关:何时在多线程中使用volatile?同样适用于C11及其后续版本。虽然不是必需的,但在C11之前被用来实现无锁原子加载/存储。 - Peter Cordes
C#Java类似:*“volatile”关键字有什么用途?* - Peter Mortensen
一个更早的(2008-09-16):为什么会有volatile关键字? - Peter Mortensen
18个回答

9

Volatile在IT技术中也是非常有用的,特别是当你想要强制编译器不优化某个特定的代码序列(例如编写微基准测试)时。


8
在Dennis Ritchie设计的语言中,除了那些未被取地址的自动对象之外,对任何对象的访问都会表现得好像计算了该对象的地址,然后读取或写入该地址处的存储。这使得该语言非常强大,但严重限制了优化的机会。
虽然可能有可能禁止编译器假设可寻址对象永远不会以奇怪的方式改变,但这样的假设对于C程序中绝大多数对象来说是合适和有用的,而为所有需要这种假设的对象添加限定符则是不切实际的。另一方面,有些程序需要使用一些对象,这些对象并不满足这种假设。为了解决这个问题,标准规定编译器可以假设未声明为“volatile”的对象的值不会以超出编译器控制范围或超出合理编译器理解范围的方式被观察或更改。
因为不同的平台可能以不同的方式观察或修改编译器无法控制的对象,所以对于这些平台的优质编译器在处理volatile语义时应该有所区别。不幸的是,由于标准未建议针对低级编程意图的优质编译器应该如何处理volatile,以便识别特定读/写操作对该平台上的任何相关影响,许多编译器在这方面做得不够好,使得处理像后台I/O这样的事情变得更加困难,即使是高效的处理方式也可能被编译器的“优化”破坏。

句子开头的“While it might have”读起来不太顺畅。例如,你是不是想说“这样的假设将是不合适的”?也许可以重新表达一下? - Peter Mortensen
@PeterMortensen:是的,那确实有点混乱。希望现在好一些了。 - supercat
@PeterMortensen:是的,那确实有点乱七八糟。希望现在好一些了。 - undefined

6

易变意味着存储很可能随时发生变化,并且受用户程序控制之外的因素影响。

这意味着如果引用这个变量,程序应该始终检查物理地址(即,一个映射输入FIFO),而不是以缓存方式使用它。


2
没有编译器会将volatile解释为“RAM中的物理地址”或“绕过缓存”。 - curiousguy

5

简单来说,它告诉编译器不要对特定变量进行任何优化。映射到设备寄存器的变量是由设备间接修改的。在这种情况下,必须使用volatile。


4
这个答案中是否有任何新内容是之前没有提到的? - slfan

4

3
一个volatile可以从已编译代码的外部进行更改(例如,一个程序可能将一个volatile变量映射到一个内存映射寄存器)。
编译器不会对处理volatile变量的代码应用某些优化。例如,它不会将其加载到寄存器中而不写入内存。这在处理硬件寄存器时很重要。

0

正如许多人在这里正确建议的那样,volatile关键字的流行用途是跳过volatile变量的优化。

在阅读了有关volatile的内容后,最值得一提的最大优点是--防止在longjmp(非局部跳转)的情况下回滚变量。

这是什么意思?

这意味着在您执行堆栈展开以返回到某个先前的堆栈帧时,将保留最后一个值;通常在某些错误情况下。

由于这超出了本问题的范围,我不会在此详细介绍setjmp/longjmp,但值得阅读它;以及如何使用volatile功能来保留最后一个值。


关于“超出此问题范围”的回答:不,请提供一个代码示例。 - Peter Mortensen

-4
它不允许编译器自动更改变量的值。volatile变量用于动态使用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接