"volatile" 关键字对于嵌入式系统有什么意义?
What is the significance of the "volatile" key word with respect to Embedded Systems?
最近一直在自学嵌入式系统编程。我观察到在声明变量时关键字 volatile
限定符的使用率相当高?
在嵌入式系统编程中声明变量时volatile
有什么意义?
基本上应该在什么时候使用关键字。我确实阅读了有关编译器优化和关键字使用的内容。还有一些与内存映射寄存器有关的东西。
例如,我读了这个 Whosebug post 但我不明白它如何应用于嵌入式环境。更具体地说,我不明白什么时候应该使用关键字。我确实阅读了有关编译器优化和关键字使用的内容。还有一些跟内存映射寄存器相关的东西,但是不知道什么时候用
让我们看一个例子。当您查看 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
当编译器优化此代码时,它会将第二行识别为无限循环:条件为真且在其主体内永远不会为假。因此, 无限循环之后的所有内容都不需要编译,因为它永远不会 运行。因此,编译器可能会决定不在生成的汇编代码中包含该部分代码。
然而,这个PORTB
实际上链接到一个物理端口。它是一个 硬件 端口,其值可能会被外部电路改变。这意味着虽然循环看起来是无限的,但实际上并非如此。编译器不可能知道这一点。
这就是 volatile
的用武之地。当 PORTB
声明为 volatile
时,编译器不会根据 PORTB
的推理进行任何优化。它将假设其值随时可能因外部因素而改变。
volatile关键字主要是用来告诉编译器变量的值随时可能改变。它还告诉编译器不要对变量应用优化。我不是这方面的专家,但下面是我过去提到的很好的参考。
volatile is a qualifier that is applied to a variable when it is declared. It tells the compiler that the value of the variable may change at any time-without any action being taken by the code the compiler finds nearby. The implications of this are quite serious. However, before we examine them, let's take a look at the syntax.
参考:
让我换个角度来说,它与 const 关键字正好相反。
当编译器遇到任何变量的 const 限定符时,它会检查是否有任何函数或语句在初始化后被修改。因此标记错误。
volatile正好相反,这个变量可以被任何函数改变。因此编译器不应用优化。
由于中断的使用,您主要在嵌入式系统编程中看到这种情况,一些编程逻辑结构似乎是多余的。
在嵌入式系统世界中,volatile
关键字的关键方面之一是它表示可能随时更改的变量(例如 external/hardware 数据输入 - 例如ADC),因此编译器不得优化使用。
但具体来说,当与控制寄存器一起使用时,它表示读取访问实际上可能会更改数据!
作为一般经验法则,我建议在以下所有内容中使用 volatile
限定符:
- 所有硬件寄存器访问(读写)
- 所有可在多线程中访问的变量(尤其是中断处理程序)
注意:访问 volatile
不一定是原子的,因此您必须了解您的硬件和代码结构。
虽然关于优化的陈述是正确的,但对我来说似乎有点不清楚。这是真正发生的事情。
如果您不使用 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 是一个硬件端口,端口可能会改变,但寄存器不会改变,while 条件也不会改变。
循环变量(寄存器)将"out of phase"与实际变量(my_port)。
因此需要关键字volatile。
Volatile告诉C,"Don't optimize this variable into a reg, but read it each and every time you need it."
生成的指令更多,代码有点慢,但始终准确。
最近一直在自学嵌入式系统编程。我观察到在声明变量时关键字 volatile
限定符的使用率相当高?
在嵌入式系统编程中声明变量时volatile
有什么意义?
基本上应该在什么时候使用关键字。我确实阅读了有关编译器优化和关键字使用的内容。还有一些与内存映射寄存器有关的东西。
例如,我读了这个 Whosebug post 但我不明白它如何应用于嵌入式环境。更具体地说,我不明白什么时候应该使用关键字。我确实阅读了有关编译器优化和关键字使用的内容。还有一些跟内存映射寄存器相关的东西,但是不知道什么时候用
让我们看一个例子。当您查看 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
当编译器优化此代码时,它会将第二行识别为无限循环:条件为真且在其主体内永远不会为假。因此, 无限循环之后的所有内容都不需要编译,因为它永远不会 运行。因此,编译器可能会决定不在生成的汇编代码中包含该部分代码。
然而,这个PORTB
实际上链接到一个物理端口。它是一个 硬件 端口,其值可能会被外部电路改变。这意味着虽然循环看起来是无限的,但实际上并非如此。编译器不可能知道这一点。
这就是 volatile
的用武之地。当 PORTB
声明为 volatile
时,编译器不会根据 PORTB
的推理进行任何优化。它将假设其值随时可能因外部因素而改变。
volatile关键字主要是用来告诉编译器变量的值随时可能改变。它还告诉编译器不要对变量应用优化。我不是这方面的专家,但下面是我过去提到的很好的参考。
volatile is a qualifier that is applied to a variable when it is declared. It tells the compiler that the value of the variable may change at any time-without any action being taken by the code the compiler finds nearby. The implications of this are quite serious. However, before we examine them, let's take a look at the syntax.
参考:
让我换个角度来说,它与 const 关键字正好相反。 当编译器遇到任何变量的 const 限定符时,它会检查是否有任何函数或语句在初始化后被修改。因此标记错误。
volatile正好相反,这个变量可以被任何函数改变。因此编译器不应用优化。
由于中断的使用,您主要在嵌入式系统编程中看到这种情况,一些编程逻辑结构似乎是多余的。
在嵌入式系统世界中,volatile
关键字的关键方面之一是它表示可能随时更改的变量(例如 external/hardware 数据输入 - 例如ADC),因此编译器不得优化使用。
但具体来说,当与控制寄存器一起使用时,它表示读取访问实际上可能会更改数据!
作为一般经验法则,我建议在以下所有内容中使用 volatile
限定符:
- 所有硬件寄存器访问(读写)
- 所有可在多线程中访问的变量(尤其是中断处理程序)
注意:访问 volatile
不一定是原子的,因此您必须了解您的硬件和代码结构。
虽然关于优化的陈述是正确的,但对我来说似乎有点不清楚。这是真正发生的事情。
如果您不使用 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 是一个硬件端口,端口可能会改变,但寄存器不会改变,while 条件也不会改变。
循环变量(寄存器)将"out of phase"与实际变量(my_port)。
因此需要关键字volatile。
Volatile告诉C,"Don't optimize this variable into a reg, but read it each and every time you need it."
生成的指令更多,代码有点慢,但始终准确。