为什么C语言中需要volatile关键字?
volatile
告诉编译器不要优化与 volatile
变量有关的任何内容。
有至少三个常见的原因使用它,所有这些原因都涉及变量的值可以在没有代码干预的情况下改变的情况:
- 当您与自己更改值的硬件进行接口时
- 当还有另一个正在运行并使用变量的线程时
- 当可能更改变量的值的信号处理程序存在时。
假设您有一个小的硬件片段它被映射到 RAM 中的某个位置,并具有两个地址:命令端口和数据端口:
typedef struct { int command; int data; int isBusy; } MyHardwareGadget;
现在您要发送一些命令:
void SendCommand (MyHardwareGadget * gadget, int command, int data) { // wait while the gadget is busy: while (gadget->isbusy) { // do nothing here. } // set data first: gadget->data = data; // writing the command starts the action: gadget->command = command; }
看起来很简单,但它可能会失败,因为编译器可以自由地更改写入数据和命令的顺序。这将导致我们的小设备使用先前的数据值发布命令。同时看一下正在等待的忙碌循环。这个循环将被优化掉。编译器将试图聪明地只读取一次 isBusy
的值,然后进入无限循环。那不是你想要的。
解决这个问题的方法是将指针 gadget
声明为 volatile
。这样编译器被强制执行你编写的操作。它不能删除内存赋值,不能在寄存器中缓存变量,也不能更改分配的顺序
这是正确的版本:
void SendCommand (volatile MyHardwareGadget * gadget, int command, int data) { // wait while the gadget is busy: while (gadget->isBusy) { // do nothing here. } // set data first: gadget->data = data; // writing the command starts the action: gadget->command = command; }