emOsprey  鱼鹰谈单片机 2月21日

预计阅读时间: 4 分钟

和 const 不同(关于 const 可以看 const 小节),当一个变量声明为 volatile,说明这个变量会被意想不到的改变。最为典型的就是 I/O 的输入寄存器了,因为这个变量的值和外部电平有关系,一旦外部电平发生了变化,那么这个变量也就跟着变。当然还有其它寄存器也是如此,比如各种状态寄存器、定时计数器等,他们的改变是靠硬件来改变的,你的程序只能读取数据,所以一定要申明为 volatile 才行,这样当你的优化级别提高的时候,你的程序也就能保证不会因为过度优化而出现问题。

那么申明为 volatile 的变量对编译器有什么影响呢?我们知道编译器是有优化功能的,很多时候,有些变量的值在运行过程可能是不变的,如果每次访问这个变量都要从原来的内存获得变量值,那是很浪费时间的,如果你让你的的编译器不做优化,那么它每次访问这个变量都会从内存读出数据,这样不仅效率不高,代码量也会比较大,而一旦进行优化了,编译器就会把它认为不变的量保存在内部寄存器中,每次访问这个变量的时候就访问这个寄存器就可以了,这样运行效率将大大提高。所以一般写代码的时候都会有两个版本,一个是 Debug 版本,一个是 Release 版本。 Debug 版本和 Release 版本其中的一个区别就是优化级别的不同,当然他们的不同不仅仅表现在这两个方面。

首先来看看两个不同优化等级的情况下的代码情况吧:

可以看到效果还是很明显的。

首先是 Code 减少了 24.1%,RO-data 不变,RW-data 减小了 8,这是因为我在程序中申明了两个指针在程序中并没有使用,所以被优化掉了。

就是这两货占用了 8 个字节空间,现在因为优化等级提高,被优化掉了。然后ZI-data 保持不变。

这样看来,优化效果还是很明显的。但是代码运行会不会出问题,很大程度上就是volatile 的问题了。

现在看看库函数的 GPIO 结构体声明:

可以看到每个寄存器声明都是 __IO,而 __IO 最终可以看到就是 volatile:

所以每次编译器碰到申明为 volatile 的变量就不敢用寄存器中的备份了,而是从原来的内存中访问数据。

除了硬件寄存器,还有多线程共享的变量和中断服务程序的使用变量,它们都是类似的道理,都是在一个函数中可能不改变,而在其他函数(中断处理函数或者其他线程的函数)可能改变的情况,如果不声明 volatile,那么编译器看到这个变量在一个函数中不改变,就可能会只访问一次内存,然后保存到寄存器中,使用时可能都只用寄存器的副本,而一旦其他程序也对这个变量进行了写操作,它是察觉不出来的,还可能破坏这次写操作,详细内容可以看信号量部分。

说到这里,就想到一个朋友遇到的情况。当时他有一个变量在中断处理程序中进行自加,而在 main 函数中进行读取,然后调试发现这个变量读出始终为 0,根本没有改变,但能确定已经进入中断处理程序了。当时我也知道这么个情况,但是我有其他事情,就没有深究。后来他调了半天加上了 volatile 关键字才解决,之后我问他是否是编译优化级别太高了,他说优化级别根本没动过,所以他只是怀疑,并没有真正去看他编译器的级别。等我叫他再去验证的时候发现真的是优化等级高了,根本不是 level 0,而是  level 3。

当然了,如果说你懂一点汇编语言,这个问题应该比较好解决,因为不管编译器怎么优化,最终都会在汇编层面得到体现,如果发现汇编代码始终使用寄存器的副本,那么就可以判定优化基本太高了,这个时候将优化级别设置为 level 0 就没有问题了,但是最好的办法还是加上 volatile,因为以后你可能会进行优化处理也说不定呢!

-THE END-


如果觉得文章对你有帮助,欢迎转发、分享给朋友,感谢你的支持!

C语言之volatile的更多相关文章

  1. C语言关键字-volatile

    1.C语言关键字volatile     C 语言关键字volatile(注意它是用来修饰变量而不是上面介绍的__volatile__)表明某个变量的值可能在外部被改变,因此对这些变量的存取 不能缓存 ...

  2. 从C语言的volatile关键字,了解C#的volatile机制(转载)

    C#中有一个关键字volatile,一直不太明白到底什么时候才用它,只知道在多线程操作同一个变量的时候要使用volatile关键字,下面看到了一篇C语言关于volatile关键字的介绍,写的很不错,其 ...

  3. (转)c语言学习volatile

    原文网址:http://www.cnblogs.com/chio/archive/2007/11/24/970632.html 参考网址:http://www.embedu.org/Column/Co ...

  4. c语言,volatile

          一.意义: 该关键字的意义就是表示定义的变量值随时都会改变,必须从变量的地址处读取值,所以只有这个变量在使用过程中可能被改变(比如中断程序),就需要用这个关键字说明. )volatile, ...

  5. 面试问题之C++语言:volatile关键字的作用

    volatile的作用 volatile关键字是防止在共享的空间发生读取的错误.只保证其可见性,不保证原子性:使用volatile指每次从内存中读取数据,而不是从编译器优化后的缓存中读取数据,简单来讲 ...

  6. [汇编与C语言关系]5. volatile限定符

    现在研究一下编译器优化会对生成的指令产生什么影响,在此基础上介绍C语言的volatile限定符.首先看下面的C程序: /* artificial device registers */ unsigne ...

  7. C语言volatile关键字

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

  8. zz剖析为什么在多核多线程程序中要慎用volatile关键字?

    [摘要]编译器保证volatile自己的读写有序,但由于optimization和多线程可以和非volatile读写interleave,也就是不原子,也就是没有用.C++11 supposed会支持 ...

  9. C++ 中 volatile 的使用

    一.作用 volatile的作用是: 作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值. 简单地说就是防止编译器对代码进行优化.比如如下程序:XBYTE[2]=0x55;XBY ...

随机推荐

  1. pytorch API中sgd.py的学习记录

    参考:PyTorch与caffe中SGD算法实现的一点小区别 其中公式(3)(4)的符号有问题 变量对应表 程序 参考文章 buf v momentum μ d_p Δf(θ) lr ξ p θ

  2. linux_mysql学习系列

    Linux&shell系列文章:http://www.cnblogs.com/f-ck-need-u/p/7048359.html 网站架构系列文章:http://www.cnblogs.co ...

  3. jQuery获取当前checkbox的值

    背景: 目前想实现登录的“记住我”功能,需要获取当前checkbox是否被点击,百度了一通,全是多个复选框选中了哪一个的解答, 迫于无奈,自己在W3school上面查询了checkbox的所有属性,并 ...

  4. (十二)springMvc 处理图片,视频等文件的上传

    文章目录 导包 修改表单类型 配置解析器 处理上传的图片 补充一个自己写的工具类 导包 需要导入如下的包 commons-fileupload-1.3.3.jar commons-io-2.6.jar ...

  5. 9.ssh登录慢

    修改方式:使用root权限修改ssh的配置文件,vim /etc/ssh/sshd_config增加一行记录:UseDNS no修改GSSAPIAuthentication参数为 no,默认是yesP ...

  6. k8s-PV和PVC使用

    上节课我们学习了 PV 的使用,但是在我们真正使用的时候是使用的 PVC,就类似于我们的服务是通过 Pod 来运行的,而不是 Node,只是 Pod 跑在 Node 上而已,所以这节课我们就来给大家讲 ...

  7. 什么是Sprint?

    Sprint指Scrum团队完成一定数量工作所需的短暂.固定的周期.Sprint是Scrum和敏捷的核心,找到正确的Sprint周期将帮助您的敏捷团队交付更高质量的产品. “在Scrum框架中,庞大且 ...

  8. vue项目build 之后,css文件加载图片或者字体文件时404的解决。

    ExtractTextWebpackPlugin 提供了一个 options.publicPath 的 api,可以为css单独配置 publicPath . 对于用 vue-cli 生成的项目,di ...

  9. linux——环境变量

    环境变量 基本概念: 一般是指在操作系统中用来指定操纵系统运行环境的一些参数 当我们用动态库链接成功的时候,其实就是相关的环境变量帮助编译器进行查找. 环境变量通常具有某种特殊用途,还有在系统当中通常 ...

  10. 适配方案(五)适配的基础知识之设备像素比 dpr 与 1px 物理像素

    设备像素比 dpr 与 1px 物理像素 物理像素(physical pixel) 手机屏幕上显示的最小单元,该最小单元具有颜色及亮度的属性可供设置,iphone6.7.8 为:750 * 1334, ...