关于Volatile的解读

一直想看一看 volatile 的用法,之前就看过这种静态量是不会被编译器无意破坏的,但是一直没有搞彻底明白。

今天查看了大量前辈们的总结,自己又有了新的心得,写下此随笔来分享自己的心得。

最开始接触 volatile 是在STM32程序的 __IO 中,其中#define __IO  volatile

(下面一段来自维基百科对Volatile的解读)

volatile关键字用来阻止(伪)编译器认为的无法“被代码本身”改变的代码(变量/对象)进行优化。如在C语言中,

volatile关键字可以用来提醒编译器它后面所定义的变量随时有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。

(上面一段来自维基百科对Volatile的解读)

在C语言中,编译器会根据你得代码进行优化,而 volatile 最直接的就是,告诉编译器不要优化这一个变量的运算过程。

(下面图片来自维基百科)

(上面图片来自维基百科)

在汇编下,可以很明确的看出使用Volatile后编译器不会让你的代码丢失。

先说下使用volatile的好处:

1.volatile允许除了程序以外的事件来改变它的内容,比如硬件直接改变。

2.每次读取volatile的内容都是直接访问该地址的内容,不是通过cache( 高速缓冲存储器)来访问。

稍稍解释一下:1.我们告诉编译器,volatile类型的变量的确可能被外部条件改变,比如硬件设备。

2.正常情况下,如果我们不加volatile的话,在共享地址区的变量程序并不知道它什么时候被改变,你读取的只可能是cache里面的变量,而这个变量可能是过时的变量。

3.(补充)私有地址里面的内容,程序可以直接访问

 

回到我们的截图内容

#define __IO  volatile

#define uint32_t  uisigned long

如果是(volatile unsigned long *) (0x1FFF7A10),再分解看(volatile unsigned long *)是一个为随硬件需要定义的一种地址,前面加上*指针,即直接指向改地址,整个定义#define CPU_Sn0,调用的时候直接向地址寄存器写内容就好了。这是内存机制的方便性,volatile是嵌入式系统开发发一个重要特点。

再将其展开来分析:(volatile unsigned long *) (0x1FFF7A10)的意思就是将0x1FFF7A10强制转化成volatile unsigned long的指针,然后赋给CPU_Sn0就是表达CPU_Sn0为指向地址的内容了。这里是通过内存寻址访问寄存器,可以进行读/写操作。

再通过这个volatile去分析,关键字volatile 确保本条指令不会因C 编译器的优化而被省略,且要求每次直接读值。例如用while((unsigned char *)0x1FFF7A10)时,有时系统可能不真正去读0x1FFF7A10的值,而是用第一次读出的值,如果这样,那这个循环可能是个死循环。用了volatile 则要求每次都去读0x1FFF7A10的实际值。那么它就是一个固定的指针,而char *p;是一个指针变量。

再在前面加一个 “*” :则变成了变量,只不过这是一个地址固定的指针变量。

posted on 2019-07-28 17:50  乔勇刚  阅读(397)  评论(0编辑  收藏  举报

导航