7

在 C++ 中,volatile处理方式相同const:将指向 volatile 数据的指针传递给不希望volatile修饰符触发编译错误的函数。

int foo(int* bar) { /* snip */ }

int main()
{
    volatile int* baz;
    foo(baz); // error: invalid conversion from ‘volatile int*’ to ‘int*’
}

为什么危险?很明显const,移除它会破坏const正确性的修饰符;但是有“volatile正确性”这样的东西吗?我无法弄清楚如何将指向易失性数据的指针作为指向非易失性数据的指针传递会导致问题。

编辑让你们知道我为什么volatile首先使用:Mac OS X 的许多OSAtomic函数系列(用于原子增量、减量、加法、减法、比较和交换等)都带有volatile参数。

4

5 回答 5

10

因为volatile修饰符意味着编译器必须小心地按照 C 标准的“抽象机器”指定的方式实际执行易失性数据项的每次读/写。

volatile修饰符被剥离时,数据访问可以被优化掉,只要程序表现得“好像”就程序控制流的单线程观点而言发生了访问。换句话说,编译器可以将非易失性数据视为编译器,并且只有编译器可以看到并可以修改数据项(绝大多数情况下都是这种情况)。

volatile关键字告诉编译器其他东西(硬件或另一个执行线程)可以修改或查看该数据项,因此不允许编译器优化访问。

如果您可以将指向易失性数据的指针传递给一个函数,该函数在没有警告的情况下采用非易失性指针,则该函数可能看不到可能发生的数据变化。如果您不关心这一点,您也许可以编写一个不错的、可移植的解决方法(取决于对foo()数据的处理方式):

int foo(int* bar) { /* snip */ }

int main()
{
    volatile int* baz;

    int tmp = *baz;
    foo(&tmp);
    *baz = tmp;
}
于 2010-08-04T23:52:46.480 回答
5

编译器不仅可以优化对非易失性变量的访问,还可以预测性/推测性地更新它们,只要程序的顺序执行不受影响。

如果对 volatile 变量的虚假写入不会破坏您的设计,那么它可能在任何情况下都不需要是 volatile。

例如,C++03 编译器转换是完全合法的

int result;
void sum_if_all_positive( std::array<N> ary )
{
    int sum = 0;
    result = -1;
    for( int i = 0; i < N; ++i ) {
        if (ary[i] < 0) return;
        sum += ary[i];
    }
    result = sum;
}

进入

int result;
void sum_if_all_positive( std::array<N> ary )
{
    result = 0;
    for( int i = 0; i < N; ++i ) {
        if (ary[i] < 0) { result = -1; return; }
        result += ary[i];
    }
}

(虽然这样的改变会提供比只在少数具有廉价内存访问和很少寄存器的架构上注册 sum 更好的性能。我想到了 Microchip PIC 架构。)

于 2010-08-05T00:03:56.077 回答
0

好吧,在foo()编译器中不再知道baz(或更严格地说bar)是 volatile ,因此可能会尝试应用一些不适当的优化。

于 2010-08-04T23:49:10.587 回答
0

volatile关键字意味着每次都应该从内存中加载和存储该值。

考虑代码:

int foo(int* bar) { 
    while(*bar){ 
        //Do something...
    }
}

int main()
{
    volatile int num = 1;
    volatile int* baz = &num;
    //Start a seperate thread to change *baz evenutally... 
    foo(baz);
}

当编译器看到 while 循环,并且知道 bar 所指向的总是 1 时,为什么每次都要检查呢?每次检查都会非常浪费。 volatile确保编译器每次都执行此检查,因此当另一个线程更改值时,while循环退出。

于 2010-08-04T23:56:59.480 回答
-1

是的,有“不稳定的正确性”之类的东西

它用于帮助确保多线程代码的安全性。

于 2012-11-10T05:48:20.380 回答