在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*’
}
Run Code Online (Sandbox Code Playgroud)
为什么危险?对于const修饰符来说,删除它可能会破坏const正确性; 但是有" volatile正确性"之类的东西吗?我无法弄清楚如何将指向易失性数据的指针作为非易失性数据的指针传递可能会导致问题.
编辑只是让你们知道我为什么volatile在第一时间使用:许多Mac OS X的OSAtomic函数系列(用于原子增量,减量,加法,减法,比较和交换等)都需要volatile参数.
因为volatile修饰符意味着编译器必须注意实际执行易失性数据项的每次读/写操作,就像C标准的"抽象机器"指定的那样.
当volatile修改器被剥离时,只要程序表现为"好像"访问就控制程序流程的单线程视点而言,就可以优化数据访问.换句话说,编译器可以处理非易失性数据,就像编译器和只有编译器可以看到并且可以修改数据项一样(在绝大多数情况下就是这种情况).
该volatile关键字告诉编译器其他内容(硬件或其他执行线程)可以修改或查看该数据项,因此不允许编译器优化访问.
如果您可以将指向易失性数据的指针传递给在没有警告的情况下使用非易失性指针的函数,则该函数可能看不到可能发生的数据的更改.如果你不关心这一点,你可以编写一个漂亮的,可移植的解决方法(取决于对foo()数据的作用):
int foo(int* bar) { /* snip */ }
int main()
{
volatile int* baz;
int tmp = *baz;
foo(&tmp);
*baz = tmp;
}
Run Code Online (Sandbox Code Playgroud)
编译器不仅可以优化对非易失性变量的访问,只要程序的顺序执行不受影响,它就可以预测性地/推测性地更新它们.
如果对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;
}
Run Code Online (Sandbox Code Playgroud)
成
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];
}
}
Run Code Online (Sandbox Code Playgroud)
(虽然这种改变提供的性能比仅在少数具有廉价存储器访问和极少数寄存器的架构上注册总和的性能更好.想到Microchip PIC架构.)