我最近一直在努力学习嵌入式系统编程。我在声明变量时观察到关键字volatile
限定符的使用率相当高?
在嵌入式系统编程中声明变量时volatile
有什么意义?
基本上应该使用关键词。我确实读过有关编译器优化和关键字使用的内容。还有与内存映射寄存器有关的东西。
例如,我读了这篇StackOverflow post,但我并不了解它在嵌入式环境中的应用。更具体地说,我不明白何时应该使用关键词。我确实读过有关编译器优化和关键字使用的内容。还有一些与内存映射寄存器有关的东西,但我不知道何时使用它。
答案 0 :(得分:10)
让我们来看一个例子。当您查看PIC微控制器的C头文件时,您将看到许多元素被声明为volatile
:
extern volatile unsigned char PORTB @ 0x006;
如您所读,volatile
关键字禁用编译器优化。假设您编写了一个执行以下操作的程序:
PORTB = 0x00; // set all of port B low
while (PORTB == 0x00); // wait for any pin to get high
// do something else
当编译器优化此代码时,它会将第二行识别为无限循环:条件为true且永远不会在其正文中变为false。因此,无限循环之后的所有都不需要编译,因为它永远不会被运行。因此,编译器可能决定不在生成的汇编代码中包含该部分代码。
但是,此PORTB
实际上与物理端口相关联。它是硬件端口,其值可能会被外部电路改变。这意味着虽然循环似乎是无限的,但它并不是必须的。编译器可能不知道这一点。
volatile
所在的位置。当PORTB
被声明volatile
时,编译器不会根据PORTB
的推理进行任何优化。它将假设其值可能随时由外部因素改变。
答案 1 :(得分:6)
在嵌入式系统领域,volatile
关键字的一个关键方面是它表示可能随时改变的变量(例如外部/硬件数据输入 - 例如ADC)和因此编译器不得优化使用。
但具体而言,当与控制寄存器一起使用时,它表明读取访问实际上可能会改变数据!
作为一般经验法则,我建议在以下所有内容中使用volatile
限定符:
注意:访问volatile
不一定是原子的,因此您必须了解硬件和代码结构。
答案 2 :(得分:2)
主要使用 volatile 关键字告诉编译器变量的值可能随时更改。它还告诉编译器不要对变量应用优化。我对此并不是一位专家,但下面是我过去提到过的好参考。
volatile 是在声明变量时应用于变量的限定符。它告诉编译器变量的值可能随时发生变化 - 编译器在附近找不到任何代码。这种影响非常严重。但是,在我们检查它们之前,让我们看一下语法。
参考:
答案 3 :(得分:1)
让我从其他角度来看,它与 const 关键字正好相反。 当编译器遇到任何变量的 const 限定符时,它会检查是否在初始化时修改了任何函数或语句。因此标志错误。
易失性正好相反,这个变量可以通过任何函数改变。因此编译器不应用优化。
由于使用了中断,您在嵌入式系统编程中看到了这一点,并且一些编程逻辑结构似乎是多余的。
答案 4 :(得分:0)
尽管关于优化的陈述是正确的,但对我来说似乎有些不清楚。这是真正发生的事情。
如果您不使用volatile关键字,则C可能会将变量优化为当前未使用的寄存器。这样可以减少汇编指令,并且代码执行速度更快。
例如,考虑以下...
extern int my_port; // my_port is defined in a different module somewhere
// presumably a memory mapped hardware port
while (my_port > 0) {so stuff}
编译器可能决定仅在实际的while语句之前将my_port读入寄存器一次,然后每次测试my_port时,它只会查看寄存器而不是内存位置。
但是,如果my_port是硬件端口,则该端口可能会更改,但注册不会更改,而条件条件不会更改。
循环变量(寄存器)将与实际变量(my_port)“异相”。
因此需要关键字volatile。
Volatile告诉C,“不要将此变量优化为reg,而是每次需要时都读取它。”
生成的指令更多,代码稍慢一些,但始终准确。