c语言volatile关键字的作用是什么?

1. 什么是volatile关键字?

在C语言中,volatile是一种类型修饰符,用于告诉编译器,尤其是优化器,相应的变量是易变的,需要特殊对待。在C语言中,变量频繁地被访问和修改,因此这些变量的值可能会被缓存到寄存器中,而非内存中。这种情况下,volatile关键字的作用就显现出来了。

2. volatile关键字的作用是什么?

2.1 防止编译器优化

一些特殊的变量,如外设寄存器等,其值经常会被改变。如果不告诉编译器这些变量是易变的,那么编译器就有可能将其优化掉,从而导致程序运行出错。因此需要用volatile关键字来告诉编译器这些变量的值不能被优化掉。

int flag = 0;

while(flag == 0){}

如果把flag这个变量去掉volatile修饰,编译器就会按照自己的优化方式,将该变量缓存在CPU寄存器中,等待flag改变状态。所以,在这种情况下,while循环就成为了一个死循环,程序无法退出。代码如下:

#include<stdio.h>

int main(){

int flag = 0;

while(flag == 0){}

printf("Hello world!");

return 0;

}

用GCC编译器编译后,程序无法退出。

而加入volatile后,编译器就不会做这样的优化,每次都会在内存中进行读取,从而获得最新变量值,程序可以正常执行结束。代码如下:

#include<stdio.h>

volatile int flag = 0;

int main(){

while(flag == 0){}

printf("Hello world!");

return 0;

}

2.2 防止编译器指令重排

编译器对代码进行优化时,往往会根据自己的判断优化指令的先后执行顺序,来提升程序的执行速度。然而,这种指令重排有可能会影响程序的正确性。对于一些涉及多线程的编程场景,volatile关键字的作用就体现出来了。因为多线程的执行顺序是无法控制的,因此需要volatile关键字来阻止编译器的指令重排。

volatile int flag = 0;

int value = 0;

void foo(){

value = 42;

flag = 1;

}

void bar(){

if(flag){

printf("value=%d\n", value);

}

}

int main(){

foo();

bar();

return 0;

}

如果把flag和value这两个变量去掉volatile修饰,编译器就有可能把赋值操作和flag的赋值操作交换位置,导致bar函数输出value的值为0。因此,在这种情况下,需要使用volatile关键字来保证程序的正确性。

2.3 防止编译器从寄存器中读取变量的值

对于一些涉及硬件设备IO的程序,需要从设备中读取特定的值。如果从IO设备中读取的这些值只存储在硬件寄存器中,而不是存储在内存中,则编译器会从寄存器中直接读取这些值,而无视IO设备。而volatile关键字可以解决这个问题,它告诉编译器每次操作这些变量时都必须从内存中读取。

2.4 总结

综上所述,volatile关键字的作用主要有三个:防止编译器进行优化、防止编译器指令重排和防止编译器从寄存器中读取变量的值。在一些特殊的编程场景下,如多线程编程、硬件设备IO等场景中,使用volatile关键字可以有效保证程序的正确性。但是,在一般的编程场景下,不要滥用volatile关键字,因为它会导致程序的性能降低。

后端开发标签