📜  了解C语言中的“易失性”限定词设置1(简介)

📅  最后修改于: 2021-05-25 21:04:44             🧑  作者: Mango

尽管有大量关于C语言的文献,但是“ volatile ”关键字还是不被很好地理解(即使是经验丰富的C程序员也是如此)。我们认为,这样做的主要原因是由于在以高级语言编写的典型C程序中没有“ volatile ”变量的实际用例。基本上,除非您使用C进行一些底层硬件编程,否则在被限定为“ volatile ”的情况下,您可能不会使用变量。所谓低级编程,是指一段C代码,用于处理外围设备,与硬件交互的IO端口(主要是内存映射的IO端口),中断服务程序(ISR)。这就是为什么没有一个简单的示例C语言程序可以很容易地展示“ volatile ”关键字的确切效果的原因。

实际上,在本文中,如果我们能够解释“ volatile ”的含义和目的,它将为进一步研究和使用C中的“ volatile”奠定基础。要理解“ volatile”,我们首先需要掌握一些知识。关于编译器对C程序所做的工作的背景知识。从高层次上讲,我们知道编译器会将C代码转换为机器代码,从而使可执行文件可以在没有实际源代码的情况下运行。与其他技术类似,编译器技术也发展了很多。在将源代码转换为机器代码时,编译器通常会尝试优化输出,以便最终需要执行较少的机器代码。一种这样的优化是删除不需要的用于访问变量的机器代码,从编译器的角度来看,这些代码没有改变。假设我们有以下代码:

uint32 status = 0;
  
while (status == 0)
{
  /*Let us assume that status isn't being changed 
  in this while loop or may be in our whole program*/
  
  /*So long as status (which could be reflecting 
  status of some IO port) is ZERO, do something*/
}

一个优化的编译器会看到状态并没有被while循环更改。因此,无需在每次循环迭代后一次又一次访问状态变量。因此,编译器会将此循环转换为无限循环,即while(1),因此不需要读取机器码的状态。请注意,编译器并不知道状态是一个特殊变量,可以在任何时间从当前程序外部更改该变量,例如,某些外围设备发生了IO操作,其设备IO端口已被内存映射到该变量。因此,实际上,我们希望编译器在每次循环迭代之后访问状态变量,即使该状态变量未被编译器正在编译的程序修改。

可以说我们可以关闭此类程序的所有编译器优化,以免遇到这种情况。由于多种原因,这不是一个选择,例如
A)每个编译器实现都是不同的,因此它不是可移植的解决方案
B)仅仅因为一个变量,我们不想放弃编译器在程序其他部分所做的所有其他优化。
C)通过关闭所有优化,我们的低级程序无法按预期运行,例如,大小增加过多或执行延迟。

这就是“易失性”的体现。基本上,我们需要指示编译器状态为特殊变量,以便不允许对该变量进行此类优化。这样,我们将定义变量如下:

volatile uint32 status = 0;

为了简化说明目的,我们选择了上面的示例。但一般来说, volatile与以下指针一起使用:

volatile uint32 * statusPtr = 0xF1230000

在这里, statusPtr指向一个内存位置(例如,用于某些IO端口),在该位置上内容可以在任何时间从某个外围设备更改。请注意,我们的程序可能对该内存何时更改没有任何控制或知识。因此,我们将其设置为“ volatile ”,以便编译器不会对由statusPtr指向的volatile变量执行优化。

在关于“ volatile ”的讨论中,我们引用了C语言标准,即ISO / IEC 9899 C11 –第6.7.3节。

“具有挥发限定类型的对象可以以实现方式未知的方式进行修改,或者具有其他未知的副作用。”

“易失性声明可用于描述与内存映射的输入/输出端口相对应的对象或由异步中断函数访问的对象。除非经评估表达式的规则允许,否则对这样声明的对象的操作不应被实现“优化”或重新排序。

基本上,C标准说,“易失性”变量可以在程序外部进行更改,这就是为什么编译器不应该优化其访问权限的原因。现在,您可以猜测程序中包含太多“易失性”变量也会导致越来越少的编译器优化。我们希望它为您提供有关“ volatile”的含义和目的的足够背景知识。

在本文中,我们希望您采用“易失性变量–>不要对该变量进行编译器优化”的概念!

下面的文章通过更多示例说明了volatile。
了解C语言中的“易变”限定词第2组(示例)

想要从精选的最佳视频中学习和练习问题,请查看《基础知识到高级C的C基础课程》。