为什么C中需要挥发性?它的用途是什么?它会做什么?
当前回答
我会提到另一个挥发物很重要的场景。
假设您为更快的I/O对文件进行内存映射,并且该文件可以在幕后更改(例如,该文件不在您的本地硬盘驱动器上,而是通过网络由另一台计算机提供)。
如果您通过指向非易失性对象的指针(在源代码级别)访问内存映射文件的数据,那么编译器生成的代码可以多次获取相同的数据,而您却不知道它。
如果该数据碰巧发生了变化,您的程序可能会使用两个或多个不同版本的数据,并进入不一致的状态。如果程序处理不受信任的文件或来自不受信任位置的文件,这不仅会导致程序的逻辑不正确行为,而且还会导致可利用的安全漏洞。
如果您关心安全性,这是一个需要考虑的重要场景。
其他回答
它不允许编译器自动改变变量的值。易失性变量用于动态使用。
Volatile告诉编译器你的变量可以通过其他方式被改变,而不是通过访问它的代码。例如,它可能是一个I/ o映射的内存位置。如果在这种情况下没有指定这一点,一些变量访问可以被优化,例如,它的内容可以保存在寄存器中,并且内存位置不会再次读入。
volatile在C语言中实际上是为了不自动缓存变量的值而存在的。它会告诉编译器不要缓存这个变量的值。因此,每次遇到给定的volatile变量时,它都会生成代码从主存中获取它的值。之所以使用这种机制,是因为该值在任何时候都可以被操作系统或任何中断修改。所以使用volatile可以帮助我们每次都重新访问值。
在我看来,你不应该对volatile期望太高。为了说明这一点,看看尼尔斯·派彭布林克(Nils Pipenbrinck)的高票数回答中的例子。
我想说,他的例子并不适用于volatile。Volatile只用于: 阻止编译器进行有用和理想的优化。这与线程安全、原子访问甚至内存顺序无关。
在这个例子中:
void SendCommand (volatile MyHardwareGadget * gadget, int command, int data)
{
// wait while the gadget is busy:
while (gadget->isbusy)
{
// do nothing here.
}
// set data first:
gadget->data = data;
// writing the command starts the action:
gadget->command = command;
}
gadget->data = gadget->command = command之前的数据仅由编译器在编译后的代码中保证。在运行时,处理器仍然可能根据处理器架构对数据和命令分配进行重新排序。硬件可能会得到错误的数据(假设gadget映射到硬件I/O)。数据和命令分配之间需要内存屏障。
Volatile也很有用,当你想强制编译器不优化特定的代码序列时(例如编写一个微基准测试)。