代码之家  ›  专栏  ›  技术社区  ›  zneak

为什么去除挥发性物质是危险的?

  •  6
  • zneak  · 技术社区  · 15 年前

    在C++中, volatile 是以同样的方式对待的 const is:将指向易失性数据的指针传递给不希望 不稳定的 修饰符触发编译错误。

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

    为什么很危险?很明显,对于 常数 移除它会破坏 常数 不稳定的 “正确性”?我不知道如何将指向易失性数据的指针作为指向非易失性数据的指针传递会导致问题。

    编辑 只是想让你们知道我为什么用 首先:许多Mac OS X OSAtomic 函数族(用于原子增量、减量、加法、减法、比较和交换等)采用 不稳定的 论据。

    5 回复  |  直到 15 年前
        1
  •  5
  •   Ben Voigt    12 年前

    如果对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更好的性能。我想到了微型芯片PIC架构。)

        2
  •  9
  •   Michael Burr    15 年前

    因为 volatile 修饰符意味着编译器必须注意实际执行易失性数据项的每个读/写操作,就像C标准的“抽象机”指定的那样。

    不稳定的 修饰符被剥离,数据访问可以被优化掉,只要程序表现得“好像”访问就发生在程序控制流的单线程视点上。换言之,编译器可以将非易失性数据块视为编译器,只有编译器才能看到并修改数据项(绝大多数情况下都是这样)。

    这个 不稳定的

    如果可以将指向易失性数据段的指针传递给一个函数,而该函数在没有警告的情况下使用非易失性指针,则该函数可能看不到可能发生的数据更改。如果你不关心这个,你也许可以编写一个好的,可移植的解决方案(取决于什么) foo()

    int foo(int* bar) { /* snip */ }
    
    int main()
    {
        volatile int* baz;
    
        int tmp = *baz;
        foo(&tmp);
        *baz = tmp;
    }
    
        3
  •  0
  •   anon anon    15 年前

    嗯,在 foo() 编译器不再知道这一点 baz bar )是不稳定的,因此可能会尝试应用一些不适当的优化。

        4
  •  0
  •   KLee1    15 年前

    这个 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时。为什么每次都要检查?每次检查都是非常浪费的。 不稳定的 确保编译器 每次都执行此检查,因此当另一个线程更改值时 while 回路出口。