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. 淘宝客类别id大全

    汽车/用品/配件/改装 例 [ID:26] 家居饰品 例 [ID:50020808] 特色手工艺 例 [ID:50020857] 景点门票/度假线路/旅游服务 例 [ID:50025707] 男装 例 ...

  2. 用java转换文件的字符集

    中文乱码真的是让人很头疼问题,有了这个方法应该能缓解这种头疼,用的是递归方式查找文件,直接在原文件中修改,小心使用(在本地测试效果有点诡异呀,没有达到预期效果). package com.hy.uti ...

  3. 【AtCoder】M-SOLUTIONS Programming Contest

    M-SOLUTIONS Programming Contest A - Sum of Interior Angles #include <bits/stdc++.h> #define fi ...

  4. Git在IDEA工具中快捷拉取代码

    在拥有GitLab账号之后, 进入IDEA中,点击vcs菜单-->Checkout from Version Control-->Git 随后会出现一个弹框,输入git上的项目地址点击CL ...

  5. spring mvc 简单实现及相关配置实现

    配置文件 actio.xml <?xml version="1.0" encoding="UTF-8"?> <controller> & ...

  6. 笔记-3:mysql数据定义

    1.定义数据库 1.1 创建数据库:创建数据库是在系统磁盘上划分一块区域用于数据的存储和管理. # 基本语法: create {database | schema} [if not exists] d ...

  7. python+socket实现网络信息交互及文件传输

    Socket 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. Socket又称"套接字",应用程序通常通过"套接字" ...

  8. QAbstractItemModel使用样例与解析(Model::index使用了createIndex,它会被销毁吗?被销毁了,因为栈对象出了括号就会被销毁)

    参考:qt源码 qstandarditemmodel_p.h qstandarditemmodel.h qstandarditemmodel.cpp qabstractitemmodel.h qabs ...

  9. [Tarjan系列] Tarjan算法求无向图的双连通分量

    这篇介绍如何用Tarjan算法求Double Connected Component,即双连通分量. 双联通分量包括点双连通分量v-DCC和边连通分量e-DCC. 若一张无向连通图不存在割点,则称它为 ...

  10. git 公钥的使用

    码云 https://gitee.com/ ,之前在教程视频中看到使用 码云  今天自己也撸了一把.第一次使用.打开官方网站看到免费开通企业版,就点了这个原本以为需要填写很多资料,实际操作下来,就一个 ...