volatile限定符——CPP

volatile 限定符

为什么使用volatile

根据CPP之父的说法:

A volatile specifier is a hint to a compiler that an object may change its value in ways not specified by the language so that aggressive optimizations must be avoided.

直接处理硬件的程序往往会包含这样的数据元素,这些元素可能会被程序之外的过程控制,因此对象的值很有可能会被程序之外修改,这时应该把对象声明为volatile

声明为volatile的变量在编译器访问它时,编译器就不再对它做任何优化,从而提供稳定的地址访问。例如,系统总是会重新从内存中读取该数据,即便在它前面的指令中已经都读取过数据并存储在寄存器中。

一般来说,volatile用在以下几个方面:

  • 中断服务程序中修改的的供其它程序检测的变量需要加volatile;
  • 多任务环境下多任务共同分享的标志需要加volatile;
  • 存储器映射的硬件寄存器需要加volatile(因为每次的读写意义不同);

通常情况下,是在多线程共享变量时,一个线程改变变量,使得该变量对其它线程visible。也可以避免当两个线程用到同一个变量时,一个线程使用寄存器中的变量,一个线程使用内存中的变量;

volatile指针

volatile与const之间没有什么影响,一个变量可以既是volatile的也是const。

1
2
3
4
volatile int v; // v是一个volatile的int
int *volatile vip; // vip是一个volatile指针,指向int
volatile int* ivp; // ivp是一个指针,它指向volatile int
volatile int *volatile vivp; //vivp是一个volatile指针,指向volatile int

同const,只能将一个volatile的对象赋予一个指向volatile的指针。

拷贝构造

与const不同,我们不能使用合成的拷贝/移动构造函数以及赋值运算符来初始化一个volatile对象。因为合成的成员接受的实参是一个非volatile的常量引用,我们不能将一个非volatile引用绑定到volatile对象上。

因此我们必须自定义拷贝或者赋值操作:

1
2
3
4
5
6
class Foo{
public:
Foo(const volatile Foo&);
Foo& operator=(volatile const Foo&);//将一个volatile对象赋值给非volatile对象
Foo& operator=(volatile const Foo&) volatile;//将一个volatile对象赋值给volatile对象
}