INTPAND = INTPAND; // 清中断
INTPAND = INTPAND;这种操作,如果没有 volatile 修饰,编译器就很有可能会去掉 INTPAND = INTPAND;,相当于没这句话了。
在嵌入式编程中,当地址是 io 端口的时候,读写这个地址是不能对它进行缓存的(有cache才),比如写这个 io 端口的时候,如果没有 volatile 修饰,编译器会先把值先写到一个缓冲区,到一定时候再写到 io 端口,这样就不能使数据及时的写到 io 端口,有了 volatile 修饰就会直接写到 io 端口,从而避免了读写 io 端口的延时。
编译器对代码的优化
再说说编译器的优化,CPU 在执行的过程中,因为访问内存的速度远没有 cpu的执行速度快,为了提高效率,引入了高速缓存 cache。
C 编译器在编译时如果不知道变量会被其它外部因素(操作系统、硬件或者其它线程)修改,那么就会对该变量进行优化(当然也有些 IDE 可以设置优化等级),这个变量在 CPU 的执行过程中会被放到高速缓存 cache 去,进而达到对变量的快速访问。
在一些寄存器变量或数据端口的使用中,因为寄存器变量本身也是靠 cache 来处理,为了避免引起错误,也可以使用 volatile 修饰符。
如果变量是被外部因素改变,那么 cpu 就无法判断出这个变量已经被改变,那么程序在执行的过程中如果使用到该变量,还会继续使用cache中的变量(已经改变),需要到内存地址中更新,所以变量在执行的过程中不能被放到cache中。
总结
使用 volatile 的目的就是让对 volatile 变量的存取不能缓存到寄存器,每次使用时需要重新存取。在嵌入式开发中这种用法很常见也很关键,需要掌握。
2001 年创刊,20 年技术见证
《新程序员001:开发者黄金十年》
重磅来袭