【问题标题】:What is the significance of the "volatile" key word with respect to Embedded Systems?相对于嵌入式系统,“volatile”关键字的意义是什么?
【发布时间】:2015-08-07 20:31:39
【问题描述】:

我最近一直在自学嵌入式系统编程。我观察到声明变量时关键字volatile 限定符的使用率相当高?

在嵌入式系统编程中声明变量时volatile有什么意义?

基本上什么时候应该使用关键字。我确实读过一些关于编译器优化和关键字使用的内容。还有一些与内存映射寄存器有关的东西。

例如,我读过这个StackOverflow post,但我不明白它是如何应用于嵌入式环境的。更具体地说,我不明白什么时候应该使用关键字。我确实读过一些关于编译器优化和关键字使用的内容。还有一些与内存映射寄存器有关的东西,但我不明白什么时候使用它。

【问题讨论】:

标签: embedded c


【解决方案1】:

让我们看一个例子。当您查看 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 的推理进行任何优化。它会假设它的值可能随时被外部因素改变。

【讨论】:

    【解决方案2】:

    在嵌入式系统领域,volatile 关键字的关键方面之一是它表示一个随时可能改变的变量(例如外部/硬件数据输入 - 例如 ADC),因此编译器不得优化使用。

    但具体来说,当与控制寄存器一起使用时,它表明读取访问实际上可能会更改数据!

    作为一般经验法则,我建议在以下所有内容中使用 volatile 限定符:

    • 所有硬件寄存器访问(读取和写入)
    • 可在多个线程中访问的所有变量(尤其是中断处理程序)

    注意:访问volatile 不一定是原子的,因此您必须了解您的硬件和代码结构。

    【讨论】:

      【解决方案3】:

      volatile 关键字主要用于告诉编译器变量的值可能随时更改。它还告诉编译器不要对变量应用优化。我不是这方面的专家,但下面是我过去提到的很好的参考。

      volatile 是在声明变量时应用于变量的限定符。它告诉编译器变量的值可能随时改变——编译器在附近找到的代码不会采取任何行动。这带来的影响是相当严重的。不过,在我们检查它们之前,让我们先看看语法。

      参考:

      【讨论】:

        【解决方案4】:

        让我换个角度来看,它与 const 关键字完全相反。 当编译器遇到任何变量的 const 限定符时,它会检查是否有任何函数或语句在初始化后被修改。因此标记错误。

        Volatile 正好相反,这个变量可以被任何函数改变。因此编译器不应用优化。

        由于使用中断,您主要在嵌入式系统编程中看到这一点,并且某些编程逻辑结构似乎是多余的。

        【讨论】:

        • 这是不准确的。它可以通过您正在编写的程序之外的因素来更改。可以被任何函数更改的变量称为全局范围变量,这与它们是否被声明为volatile 是正交的。
        【解决方案5】:

        虽然关于优化的陈述是正确的,但对我来说似乎有点不清楚。这是真正发生的事情。

        如果您不使用 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 条件也不会改变。

        循环变量(寄存器)将与实际变量(my_port)“异相”。

        因此需要关键字 volatile。

        Volatile 告诉 C,“不要将此变量优化为 reg,而是在每次需要时读取它。”

        生成的指令更多,代码有点慢,但总是准确的。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-10-09
          • 1970-01-01
          • 2011-03-26
          • 1970-01-01
          • 1970-01-01
          • 2010-09-12
          相关资源
          最近更新 更多