易变量

volatile 关键字告诉编译器,由于外部条件,变量的值可能随时发生变化,而不仅仅是程序控制流的结果。

编译器不会优化与 volatile 变量有关的任何内容。

volatile int foo; /* Different ways to declare a volatile variable */
int volatile foo;

volatile uint8_t * pReg; /* Pointers to volatile variable */
uint8_t volatile * pReg;

使用 volatile 变量有两个主要原因:

  • 与具有内存映射 I / O 寄存器的硬件接口。
  • 使用在程序控制流程外修改的变量时(例如,在中断服务程序中)

我们来看看这个例子:

int quit = false;

void main() 
{
    ... 
    while (!quit) {
      // Do something that does not modify the quit variable
    } 
    ...
}

void interrupt_handler(void) 
{
  quit = true;
}

允许编译器注意 while 循环不修改 quit 变量并将循环转换为无限的 while (true) 循环。即使在 SIGINTSIGTERM 的信号处理程序上设置了 quit 变量,编译器也不知道。

quit 声明为 volatile 将告诉编译器不优化循环,问题将得到解决。

访问硬件时会出现同样的问题,如本例中所示:

uint8_t * pReg = (uint8_t *) 0x1717;

// Wait for register to become non-zero 
while (*pReg == 0) { } // Do something else

优化器的行为是读取变量的值一次,不需要重新读取它,因为值总是相同的。所以我们最终得到了一个无限循环。为了强制编译器执行我们想要的操作,我们将声明修改为:

uint8_t volatile * pReg = (uint8_t volatile *) 0x1717;