为什么C中需要挥发性?它的用途是什么?它会做什么?
当前回答
volatile的边缘用法如下。假设你想计算一个函数f的数值导数:
double der_f(double x)
{
static const double h = 1e-3;
return (f(x + h) - f(x)) / h;
}
问题是由于舍入误差,x+h-x通常不等于h。想想看:当你减去非常接近的数字时,你会丢失很多有效的数字,这可能会破坏导数的计算(想想1.00001 - 1)
double der_f2(double x)
{
static const double h = 1e-3;
double hh = x + h - x;
return (f(x + hh) - f(x)) / hh;
}
但是根据您的平台和编译器开关的不同,该函数的第二行可能会被积极优化的编译器删除。所以你可以写
volatile double hh = x + h;
hh -= x;
强制编译器读取包含hh的内存位置,从而丧失最终的优化机会。
其他回答
Volatile告诉编译器你的变量可以通过其他方式被改变,而不是通过访问它的代码。例如,它可能是一个I/ o映射的内存位置。如果在这种情况下没有指定这一点,一些变量访问可以被优化,例如,它的内容可以保存在寄存器中,并且内存位置不会再次读入。
volatile的边缘用法如下。假设你想计算一个函数f的数值导数:
double der_f(double x)
{
static const double h = 1e-3;
return (f(x + h) - f(x)) / h;
}
问题是由于舍入误差,x+h-x通常不等于h。想想看:当你减去非常接近的数字时,你会丢失很多有效的数字,这可能会破坏导数的计算(想想1.00001 - 1)
double der_f2(double x)
{
static const double h = 1e-3;
double hh = x + h - x;
return (f(x + hh) - f(x)) / hh;
}
但是根据您的平台和编译器开关的不同,该函数的第二行可能会被积极优化的编译器删除。所以你可以写
volatile double hh = x + h;
hh -= x;
强制编译器读取包含hh的内存位置,从而丧失最终的优化机会。
volatile在C语言中实际上是为了不自动缓存变量的值而存在的。它会告诉编译器不要缓存这个变量的值。因此,每次遇到给定的volatile变量时,它都会生成代码从主存中获取它的值。之所以使用这种机制,是因为该值在任何时候都可以被操作系统或任何中断修改。所以使用volatile可以帮助我们每次都重新访问值。
维基上有关于volatile的所有信息:
Volatile(计算机编程)
Linux内核的文档也对volatile做了一个很好的标记:
为什么不应该使用“volatile”类型类
volatile的另一个用途是信号处理程序。如果你有这样的代码:
int quit = 0;
while (!quit)
{
/* very small loop which is completely visible to the compiler */
}
编译器可以注意到循环体没有触及quit变量,并将循环转换为while (true)循环。即使在信号处理程序上为SIGINT和SIGTERM设置了退出变量;编译器无法知道这一点。
但是,如果quit变量被声明为volatile,编译器将被迫每次加载它,因为它可以在其他地方修改。这正是你在这种情况下想要的。