c - 为什么 C 中需要 volatile?

标签 c declaration volatile

为什么 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;
}

关于c - 为什么 C 中需要 volatile?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33348279/

相关文章:

c++ - E2321 声明未指定标签或标识符

c++ - 声明一个没有长度的静态数组,然后定义一个长度是否有效?

multithreading - 什么时候不使用 volatile?

无法删除消息队列C中的旧消息

c - C 中的声明语句

c++ - 在循环运行的函数中声明变量的开销?

c# - 为什么 Volatile.Read 会带 ref 参数?

c - Lex 程序不执行任何操作

c - C 中的多进程、 fork 和管道

c# - volatile 应该与(非并发)集合一起使用吗?