为什么这个程序中需要 volatile 关键字?

问题描述 投票:0回答:2

相关问题已被问过很多次,但它们似乎都模糊地暗示了编译器可能进行的优化,因此我们需要使用

volatile
来避免所述优化。因此,我在这里有兴趣了解编译器会进行哪些优化,或者等效地,如果我没有在下面的代码片段中包含
volatile
,该代码片段会使用内存映射接口轮询一些键盘,那么会(或可能)出现什么问题,然后,一旦收到字符,将其发送到显示器:

/* Define register addresses. */
#define KBD_DATA (volatile char *) 0x4000
#define KBD_STATUS (volatile char *) 0x4004
#define DISP_DATA (volatile char *) 0x4008
#define DISP_STATUS (volatile char *) 0x4012

void main() {
  char ch;
  /* Transfer the characters. */ 
  while (1) {
    while ((*KBD_STATUS & 0x2) == 0); 
    ch = *KBD_DATA;
    while ((*DISP_STATUS & 0x4) == 0); 
    *DISP_DATA = ch;
  } 
}

以上内容来自 Hamacher 等人的 Computer Organization。他们写下以下内容:

请注意,KBD_STATUS 和 DISP_STATUS 指针被声明为易失性的。这是必要的,因为程序仅读取相应位置的内容。没有数据写入这些位置。优化编译器可能会删除看似没有影响的程序语句,其中包括引用内存中已读取但从未写入的位置的语句。由于内存映射的 KBD_STATUS 和 DISP_STATUS 寄存器的内容会在程序外部的影响下发生变化,因此必须告知编译器这一事实。编译器不会删除涉及指针或其他声明为易失性变量的语句。

上面的重点是我的。

重新表述我上面的问题,我不明白优化编译器如何或为什么可以删除引用 KBD_STATUS 和 DISP_STATUS 的程序语句而不改变程序的语义。也就是说,为什么编译器会删除专门涉及这两个内存位置的语句?或者是 Hamacher 等人。而是说编译器可能会选择第一次从这些内存位置read(一种说法,我知道这意味着“翻译成这样的程序集......”),然后假设这个内存位置不会改变,因此不需要生成来自这些内存位置的后续汇编读取指令?

c volatile
2个回答
3
投票

他们正在总结几个案例。

  1. 变量有一个初始值。如果它从未被分配,那么它实际上是一个常量,编译器可以用该初始值替换对该变量的任何引用。
  2. 该变量没有初始值。在这种情况下,从变量中读取的值是不确定的,编译器可以将其视为具有任何值。因此它可以删除读取并使用一些任意值。
  3. 即使它没有完全删除所有读取,当存在像您显示的那样的循环时,它可以假设该值在循环期间不会改变。所以像这样的循环
while ((*KBD_STATUS & 0x2) == 0); 

可以像以前那样编译

if ((*KBD_STATUS & 0x2) == 0) {
    while (1) ; // infinite loop
}

2
投票

while ((*KBD_STATUS & 0x2) == 0);
中,程序使用
*KBD_STATUS
。这段代码没有任何改变
*KBD_STATUS
。默认情况下,C 程序中的对象不会更改,除非程序更改它。因此,如果没有
volatile
,编译器可以得出结论
*KBD_STATUS
永远不会改变,因此不需要多次从内存中读取它。因此编译器可能会优化这段代码:

if ((*KBD_STATUS & 0x2) == 0)
    while (1) {} // Loop forever.

但是,

*KBD_STATUS
可以改变。当用户输入内容时,硬件会发生变化
*KBD_STATUS
。这发生在程序代码之外。我们告诉编译器可能发生的情况的方法是将类型限定为
volatile

*DISP_DATA = ch;
中,程序中没有任何内容使用
*DISP_DATA
。默认情况下,更改程序中的对象不会导致程序外发生任何事情。并且程序中没有其他内容使用
*DISP_DATA
,因此它不会产生任何效果。因此,编译器可能会得出结论,该赋值没有执行任何操作,并将其删除。然而,改变
*DISP_DATA
会产生一些效果;它改变了显示设备。这也会发生在程序之外,因此我们使用
volatile
告诉编译器更改
*DISP_DATA
会在程序之外产生影响。

© www.soinside.com 2019 - 2024. All rights reserved.