什么是volatile关键字

volatile用于声明一个变量,告诉编译器该变量值容易发生改变,在编译、读取、存储该变量的时候都不要做任何优化,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取存储数据,不做优化,在做嵌入式开发的时候,因为有时变量地址有可能是系统的一个外设地址,他的值的变化并不在程序控制范围内,随时有可能变化,因此需要对他进行声明,每次读取或者存储直接对地址进行操作

变量如果加了 volatile 修饰,则会从内存重新装载内容,而不是直接从寄存器拷贝内容。

为什么使用volatile关键字

const 和 volatile 关键字是一种类型修饰符,两个是绝对对立的。volatile 的作用 是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。

什么时候使用volatile关键字

1、并行设备的寄存器(例如状态寄存器),存储器映射的硬件寄存器通常加volatile。

设备寄存器会在你的程序不知道或者不介入的时候发生改变,那是因为设备寄存器可以被外设硬件修改,相反,变量中的不会变。设备寄存器的内容是易失的,或者在不注意的时候被修改,当声明指向设备寄存器的指针时一定要用volatile,它会告诉编译器不要对存储在这个地址的数据进行假设,编译器在优化这个变量时应该把它看作编译时未知的。

2、一个中断服务程序中修改的供其它程序检测的变量。

由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化,例如:

static int i=0; //i 为非自动变量
int main(void)
{...while (1){if (i) dosomething();}
}
/* Interrupt service routine. */
void ISR_2(void)
{i=1;
}

程序的本意是希望 ISR_2 中断产生时,在main函数中调用 dosomething 函数,但是,由于编译器判断在 main 函数里面没有修改过 i,因此可能只执行一次对从i到某寄存器的读操作,然后每次if判断都只使用这个寄存器里面的“i副本”,导致 dosomething 永远也不会被调用。如果将变量加上 volatile 修饰,则编译器保证对此变量的读写操作都不会被优化(肯定执行)。

3、多线程应用中被几个任务共享的变量(防止编译器对代码进行优化)。

当两个线程都要用到某一个变量且该变量的值会被改变时,应该用 volatile 声明,该关键字的作用是防止优化编译器把变量从内存装入CPU寄存器中。如果变量被装入寄存器,那么两个线程有可能一个使用内存中的变量,一个使用寄存器中的变量,这会造成程序的错误执行。volatile的意思是让编译器每次操作该变量时一定要从内存中真正取出,而不是使用已经存在寄存器中的值

上面说到volatile关键字主要是防止被编译器优化或改变,那么上面是编译器优化呢?

GCC优化

通常C语言的编译器使用的是GCC编译器,他有个以下几个等级的优化

  • -O0 :(默认):没有优化。
  • -O或-O1 :优化,但不要花费太多的时间。
  • -O2 :更积极地优化
  • -O3 :最积极地优化
  • -Ofast :最高级的优化
  • -Os : 优化代码大小
  • -Og :在尽量不干扰调试的情况下优化

开启不同的优化等级,程序编译后的结果就会发生一定的变化,而volatile就是在开启优化的情况下使用,保护变量不被优化。

测试:

//示例一
#include<stdio.h>int main()
{int i = 0;i = 1;i = 2;i = 3;printf("%d\n",i);return 0;
}
//示例二
#include<stdio.h>int main()
{volatile int i = 0;i = 1;i = 2;i = 3;printf("%d\n",i);return 0;
}

使用-O默认优化等级对代码进行编译,查看汇编结果。

通过查看汇编结果,我们可以看到不使用volatile 优化后,i=0,i=1,i=2被优化,没有生成汇编的代码,只生成了i=3的汇编代码,取最后的值寻址赋值给 i 输出。而在使用volatile声明变量 优化后,每一个i 的赋值都生成了汇编代码(上图红框),没有被优化,每次赋值都重新寻址。

可以清楚的看到:使用 volatile 的代码编译未优化。如果 i 是一个寄存器变量或者表示一个端口数据就容易出错,所以说 volatile 可以保证对特殊地址的稳定访问。

编译器优化介绍
由于内存访问速度远不及CPU处理速度,为提高机器整体性能,在硬件上引入硬件高速缓存Cache,加速对内存的访问。另外在现代CPU中指令的执行并不一定严格按照顺序执行,没有相关性的指令可以乱序执行,以充分利用CPU的指令流水线,提高执行速度。以上是硬件级别的优化。再看软件一级的优化:一种是在编写代码时由程序员优化,另一种是由编译器进行优化。编译器优化常用的方法有:将内存变量缓存到寄存器;调整指令顺序充分利用CPU指令流水线,常见的是重新排序读写指令。对常规内存进行优化的时候,这些优化是透明的,而且效率很好。由编译器优化或者硬件重新排序引起的问题的解决办法是在从硬件(或者其他处理器)的角度看必须以特定顺序执行的操作之间设置内存屏障(memory barrier)Linux 提供了一个宏解决编译器的执行顺序问题。
void Barrier(void)
这个函数通知编译器插入一个内存屏障,但对硬件无效,编译后的代码会把当前CPU寄存器中的所有修改过的数值存入内存,需要这些数据的时候再重新从内存中读出。

2、volatile总是与优化有关,编译器有一种技术叫做数据流分析,分析程序中的变量在哪里赋值、在哪里使用、在哪里失效,分析结果可以用于常量合并,常量传播等优化,进一步可以消除一些代码。但有时这些优化不是程序所需要的,这时可以用volatile关键字禁止做这些优化。

volatile的本意是“易变的” 因为访问寄存器要比访问内存单元快的多,所以编译器一般都会作减少存取内存的优化,但有可能会读脏数据。当要求使用volatile声明变量值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。精确地说就是,遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问;如果不使用valatile,则编译器将对所声明的语句进行优化。(简洁的说就是:volatile关键词影响编译器编译的结果,用volatile声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不要进行编译优化,以免出错)。

volatile 常见问题

1、一个参数可以是const还可以是volatile吗?

可以。比如只读的状态寄存器。它是volatile因为它可能被意想不到的改变,它是const因为 程序不应该试图去修改它。

2、一个指针可以是volatile吗?

可以。当一个服务中子程序修改一个指向buffer的指针时。

3、下面的函数段有问题吗?

int square(volatile int *ptr)
{ return *ptr * *ptr;
}

*ptr指向一个volatile型参数,*ptr的值随时可能被改变,所以代码段返回的可能不是所期望的平方值。

4、C语言编译过程中,volatile关键字和extern关键字分别在哪个阶段起作用
       volatile应该是在编译阶段,extern在链接阶段。
       volatile关键字的作用是防止变量被编译器优化,而优化是处于编译阶段,所以volatile关键字是在编译阶段起作用。

程序编译运行阶段:C语言编译运行代码的过程_◣星河◢的博客-CSDN博客

参考文章:C语言再学习 -- 关键字volatile_聚优致成的博客-CSDN博客_volatile关键字c语言

C语言volatile 关键字相关推荐

  1. C语言volatile关键字详解

    volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据.如果没有volatile关键字,则编译器可能优化读取和存储 ...

  2. C语言-volatile关键字

    目录: 一.简述volatile 二.volatile 的含义 三.编译器优化 → C关键字volatile → memory破坏描述符 1.编译器优化介绍 2.C语言关键字volatile 3.Me ...

  3. c语言volatile关键字(详细)总结附示例讲解

    目录 一.简介 二.示例代码解析 2.1 修饰变量 2.2 修饰硬件寄存器地址 三.其他相关链接 一.简介 volatile属于C语言的关键字.开发者告诉编译器该变量是易变的,无非就是希望编译器去注意 ...

  4. C语言volatile关键字的作用

    一.前言 1.编译器优化介绍: 由于内存访问速度远不及CPU处理速度,为提高机器整体性能,在硬件上引入硬件告诉缓存Cache,加速对内存的访问.另外在现代CPU中指令的执行并不一定严格按照顺序执行,没 ...

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

    一.前言 1.编译器优化介绍: 由于内存访问速度远不及CPU处理速度,为提高机器整体性能,在硬件上引入硬件高速缓存Cache,加速对内存的访问.另外在现代CPU中指令的执行并不一定严格按照顺序执行,没 ...

  6. C语言volatile关键字—最易变的关键字

    volatile 是易变的.不稳定的意思.很多人根本就没见过这个关键字,不知道它的存在.也有很多程序员知道它的存在,但从来没用过它.我对它有种"杨家有女初长成,养在深闺人未识" 的 ...

  7. C语言学习及应用笔记之四:C语言volatile关键字及其使用

    在C语言中,还有一个并不经常使用但却非常有用的关键字volatile.那么使用volatile关键字究竟能干什么呢?接下来我将就此问题进行讨论. 一个使用volatile关键字定义变量,其实就是告诉编 ...

  8. c 语言 volatile 关键字

    一.前言 1.编译器优化介绍: 由于内存访问速度远不及CPU处理速度,为提高机器整体性能,在硬件上引入硬件高速缓存Cache,加速对内存的访问.另外在现代CPU中指令的执行并不一定严格按照顺序执行,没 ...

  9. c语言输出王字图形,专一的王子,C语言volatile关键字解析

    你明天 有一个朋友要过生日,今天把要送的礼物打包好了,一般情况下,我们明天起来不需要再次打开验证一下里面的礼物是否存在,因为我们知道,只要礼物的外包装没有动过,里面的东西应该也没有动过.其实编译器和人 ...

最新文章

  1. 征战蓝桥 —— 2014年第五届 —— C/C++A组第9题——斐波那契
  2. CF1156D 0-1-Tree(换根DP)
  3. sqlrelay mysql_php+sqlrelay+mysql实现连接池及读写负载均衡
  4. oracle提交数据按键,Oracle PLSQL - 仅提交数据库链接(Oracle PLSQL - Commit only database link)...
  5. Spring学习总结(8)——25个经典的Spring面试问答
  6. 从理解Future模式到仿写JUC的Future模式
  7. linux服务器云防火墙配置文件,Linux云服务器防火墙配置之Firewalld
  8. 软件验收测试报告报价,软件验收测试介绍和软件验收报告的费用是多少?
  9. typecho图标_使你的Typecho支持Emoji表情
  10. 截止失真放大电路_模拟电路-BJT晶体管及电路
  11. 计算机的收获初一作文,收获的作文(精选8篇)
  12. 技术博客|第8期:广告流量匹配算法在Hulu/Disney Streaming平台的实战
  13. 让HR眼前一亮:30个APP项目软件测试经验,点燃你的简历
  14. 影响人类!写入历史!疫情年最值得铭记的6个大事件
  15. 倩女幽魂次世代服务器为什么维护,8月22日停服维护公告--《倩女幽魂》手游2.0次世代全新起点...
  16. java freemarker 导出富文本到Word文档
  17. 谷歌优化有什么好处?外贸独立站如何提高谷歌优化排名?
  18. Windows XP 搭建PPPoE服务器_计算机软件及应用_IT/计算机_专业资料
  19. 微商卖潮鞋怎么引流呢?微商如何精准引流?
  20. 【常识】MySQL怎么读/正确发音

热门文章

  1. 平安金融壹账通测试技术周报(七十一期)
  2. 人工智能玩上瘾了,我要挑战电脑围棋难题,困难重重
  3. 如何将iPhone或iPad置于DFU模式
  4. 利用GpuImage打造自己的修图软件
  5. goland 修改文件的关联类型
  6. 001word行距与字体大小
  7. mysql语句统计总数_SQL一条语句统计记录总数及各状态数
  8. 最小树形图【有向图的最小生成树】
  9. 一般纳税人的认定标准
  10. 如何实现从登陆界面跳转到游戏大厅界面