为什么C语言中需要volatile关键字?

23 浏览
0 Comments

为什么C语言中需要volatile关键字?

为什么C语言中需要使用volatile?它有什么作用?会做什么?

admin 更改状态以发布 2023年5月21日
0
0 Comments

C语言中的volatile实际上是为了不自动缓存变量的值而出现的。它会告诉编译器不要缓存这个变量的值。因此,每当遇到给定的volatile变量时,它将生成从主存中获取值的代码。这种机制的使用是因为任何时候都可以由操作系统或任何中断修改值。因此,使用volatile将帮助我们每次都能访问新鲜值。

0
0 Comments

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;
}

0