为什么C中需要挥发性?它的用途是什么?它会做什么?


当前回答

维基上有关于volatile的所有信息:

Volatile(计算机编程)

Linux内核的文档也对volatile做了一个很好的标记:

为什么不应该使用“volatile”类型类

其他回答

Volatile告诉编译器你的变量可以通过其他方式被改变,而不是通过访问它的代码。例如,它可能是一个I/ o映射的内存位置。如果在这种情况下没有指定这一点,一些变量访问可以被优化,例如,它的内容可以保存在寄存器中,并且内存位置不会再次读入。

参见Andrei Alexandrescu的文章,“volatile——多线程程序员最好的朋友”

The volatile keyword was devised to prevent compiler optimizations that might render code incorrect in the presence of certain asynchronous events. For example, if you declare a primitive variable as volatile, the compiler is not permitted to cache it in a register -- a common optimization that would be disastrous if that variable were shared among multiple threads. So the general rule is, if you have variables of primitive type that must be shared among multiple threads, declare those variables volatile. But you can actually do a lot more with this keyword: you can use it to catch code that is not thread safe, and you can do so at compile time. This article shows how it is done; the solution involves a simple smart pointer that also makes it easy to serialize critical sections of code.

本文适用于C和c++。

参见Scott Meyers和Andrei Alexandrescu的文章“c++和双重检查锁定的危险”:

So when dealing with some memory locations (e.g. memory mapped ports or memory referenced by ISRs [ Interrupt Service Routines ] ), some optimizations must be suspended. volatile exists for specifying special treatment for such locations, specifically: (1) the content of a volatile variable is "unstable" (can change by means unknown to the compiler), (2) all writes to volatile data are "observable" so they must be executed religiously, and (3) all operations on volatile data are executed in the sequence in which they appear in the source code. The first two rules ensure proper reading and writing. The last one allows implementation of I/O protocols that mix input and output. This is informally what C and C++'s volatile guarantees.

volatile在C语言中实际上是为了不自动缓存变量的值而存在的。它会告诉编译器不要缓存这个变量的值。因此,每次遇到给定的volatile变量时,它都会生成代码从主存中获取它的值。之所以使用这种机制,是因为该值在任何时候都可以被操作系统或任何中断修改。所以使用volatile可以帮助我们每次都重新访问值。

Volatile意味着存储可能在任何时候被改变,而且是在用户程序控制之外被改变。这意味着如果你引用变量,程序应该总是检查物理地址(即映射的输入fifo),而不是以缓存的方式使用它。

我会提到另一个挥发物很重要的场景。

假设您为更快的I/O对文件进行内存映射,并且该文件可以在幕后更改(例如,该文件不在您的本地硬盘驱动器上,而是通过网络由另一台计算机提供)。

如果您通过指向非易失性对象的指针(在源代码级别)访问内存映射文件的数据,那么编译器生成的代码可以多次获取相同的数据,而您却不知道它。

如果该数据碰巧发生了变化,您的程序可能会使用两个或多个不同版本的数据,并进入不一致的状态。如果程序处理不受信任的文件或来自不受信任位置的文件,这不仅会导致程序的逻辑不正确行为,而且还会导致可利用的安全漏洞。

如果您关心安全性,这是一个需要考虑的重要场景。