volatile 的作用 是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。
int i = 10;
int main(void){
int a, b;
a = i;
...//伪代码,里面不含有对 a 、 b 以及 i的操作
b = i;
if(a == b){
printf("a = b");
}
else {
printf("a != b");
}
return 0;
}
如上代码,如果选择编译器优化,可能会被编译成如下代码(当然不是在C语言层面上优化,而是在汇编过程优化,只是使用C程序举例):
int i = 10;
int main(void){
int a, b;
a = i;
...//伪代码,里面不含有对 a 、 b 以及 i的操作
b = i;
printf("a = b");
return 0;
}
因为在仅仅从main主函数来看,a == b是必然的,那么在什么情况,a 和 b不是必然相等呢?
1. i 是其他子线程与主线程共享的全局变量,其他子线程有可能修改 i 值;
2. i 是中断函数与主函数共享的全局变量,中断函数有可能修改 i 值;
3. i 属于硬件寄存器,CPU可能通过硬件直接改变 i 的值(例如寄存器的标志位)
volatile 常见的几个面试题:
1、一个参数既可以是const还可以是volatile吗?
可以,例如只读的状态寄存器。它是 volatile 因为它可能被意想不到地改变。它是 const 因为 程序不应该试图去修改它。
2、一个指针可以是 volatile 吗?
可以,当一个中服务子程序修改一个指向一个 buffer 的指针时。
3、下面的函数有什么错误:
int square(volatile int *ptr)
{
return *ptr * *ptr;
}
这段代码的目的是用来返指针* ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}
总结:
volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改。volatile 提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如 果没有 volatile 关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。所以遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
谢谢大佬们的文章,转自: https://blog.csdn.net/weixin_38815998/article/details/102840096?spm=1001.2101.3001.6650.4&depth_1-utm_relevant_index=8
https://juyou.blog.csdn.net/article/details/54024070?spm=1001.2101.3001.6650.1&depth_1-utm_relevant_index=2