相关的问题已经被问过很多次了,但它们似乎都模糊地暗示了编译器可能会进行的优化,因此我们必须使用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指针被声明为易失性指针.这是必要的,因为节目只有reads个相应位置的内容.不会向这些位置写入任何数据.优化编译器可以移除看起来没有影响的程序语句,该程序语句包括引用存储器中被读取但从未写入的位置的语句.由于内存映射的KBD_STATUS和DISP_STATUS寄存器的内容在程序外部的影响下发生变化,因此必须通知编译器这一事实.编译器不会删除涉及被声明为易失性的指针或其他变量的语句.
上面的重点是我的.
换一种说法,我不明白优化编译器如何或为什么可以在不改变程序语义的情况下删除引用KBD_STATUS和DISP_STATUS的程序语句.也就是说,为什么编译器要删除特别涉及这两个内存位置的语句?或者Hamacher等人说编译器可能会 Select read(一种说法,我知道这意味着"翻译为汇编,这是这样的......"),然后假设这个内存位置不会改变,这样就不需要从这些内存位置产生后续的汇编读指令了?