嵌入式C语言中的关键字volatile

嵌入式C语言中的关键字volatile

嵌入式C语言中的关键字volatile

  • 嵌入式C语言中的关键字volatile
    • 一. volatile关键字的概念
    • 二. 不使用volatile关键字
    • 三. 编译器优化介绍
    • 四. volatile详解
    • 五. 编译器优化举例
      • 1)例:没有volatile关键字的优化
      • 2)例:volatile关键字对形参的优化
    • 六. volatile关键字使用
    • 七. 总结

一. volatile关键字的概念

是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。
volatile关键字是一种类型修饰符,用它声明的类型变量表示不可以被某些编译器未知的因素更改(优化)。volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据,而不是从寄存器或者缓存中去读取数据。

二. 不使用volatile关键字

如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。所以遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

三. 编译器优化介绍

由于内存访问速度远不及CPU处理速度,为提高机器整体性能,在硬件上引入硬件高速缓存Cache,加速对内存的访问。另外在现代CPU中指令的执行并不一定严格按照顺序执行,没有相关性的指令可以乱序执行,以充分利用CPU的指令流水线,提高执行速度。以上是硬件级别的优化。
再看软件一级的优化:一种是在编写代码时由程序员优化,另一种是由编译器进行优化。编译器优化常用的方法有:将内存变量缓存到寄存器;调整指令顺序充分利用CPU指令流水线,常见的是重新排序读写指令。 对常规内存进行优化的时候,这些优化是透明的,而且效率很好。
volatile总是与优化有关,编译器有一种技术叫做数据流分析,分析程序中的变量在哪里赋值、在哪里使用、在哪里失效,分析结果可以用于常量合并,常量传播等优化,进一步可以消除一些代码。但有时这些优化不是程序所需要的,这时可以用volatile关键字禁止做这些优化。

四. volatile详解

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

五. 编译器优化举例

我们先来看下面的两个例子。

1)例:没有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;
}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 的值(例如寄存器的标志位)
    也就说,如果满足了上面三个条件中的任何一个,那么就有可能出现a!=b的情况。这个时候为了防止编译器不必要的优化手段,就可以引入关键字volatile。

2)例:volatile关键字对形参的优化

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 常见的几个问题:
1、一个参数既可以是const还可以是volatile吗?
可以,例如只读的状态寄存器。它是 volatile 因为它可能被意想不到地改变。它是 const 因为程序不应该试图去修改它。
2、一个指针可以是 volatile 吗?
可以,当一个服务子程序修改一个指向一个 buffer 的指针时
3、C语言编译过程中,volatile关键字和extern关键字分别在哪个阶段起作用
volatile应该是在编译阶段,extern在链接阶段。
volatile关键字的作用是防止变量被编译器优化,而优化是处于编译阶段,所以volatile关键字是在编译阶段起作用。

七. 总结

总结一下,如果不使用volatile,编译器可以更好的为我们优化代码,优化为性能或者效率更好的执行代码。但反过来,如果频繁地使用volatile很可能会增加代码尺寸和降低性能,因此要合理的使用volatile。
具体在嵌入式开发过程当中,有以下两种用法:
1)告诉compiler不能做任何优化
比如要往某一地址送两指令:
代码如下:

int *ip =...; //设备地址
*ip = 1; //第一个指令
*ip = 2; //第二个指令
以上程序compiler可能做优化而成:
int *ip = ...;
*ip = 2;

结果第一个指令丢失。
如果用volatile, compiler就不允许做任何的优化,从而保证程序的原意:
volatile int *ip = …;
*ip = 1; *ip = 2;
即使你要compiler做优化,它也不会把两次付值语句间化为一。它只能做其它的优化。这对device driver程序员很有用。
2)表示用volatile定义的变量会在程序外被改变,每次都必须从内存中读取,而不能把他放在cache或寄存器中重复使用。
如复制代码 代码如下:

volatile char a;   
a=0; 
while(!a) { //do some things;   
}   
doother(); 
//如果没有 volatile则doother()不会被执行(编译器优化a的读取 认为a的值不改变恒为0)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/201003.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Python】zip

Python中的zip()函数可以将多个可迭代对象打包成一个元组序列,然后返回这些元组序列组成的迭代器。zip()函数的语法如下: zip(*iterables)其中,iterables是可迭代对象,可以是多个,也可以是一个。zip()函数将返回一个迭…

Flask 3.x AttributeError: ‘Provide‘ object has no attribute ‘xxxx‘

用了几天flask,之前都好好的,今天在规范项目结构而且加了一堆代码之后突然出现了这个错,心想不会啊,之前都好好的,chatGPT, new bing ,stackoverflow都问遍了,就是找不到正确的解决方案,回家之后一点点的rollback检查,终于发现问题所在了. 首先呢先说说一般的解决方法: 这就是…

获得矩阵对角线元素的索引 numpy.diag_indices_from()

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 获得矩阵对角线元素的索引 numpy.diag_indices_from() [太阳]选择题 请问关于以下代码的选项表述错误的是? import numpy as np a np.array([[1, 2, 3], [4, 5, 6…

算法 搜索

深度优先搜索 广度优先搜索 深搜与广搜的区别 深搜 dfs——回溯——“不撞南墙不回头” 思路 总的来说是不撞南墙不回头,相当于一个人严格按照固定的行为模式。 例如走方格,依次走上下左右,每次走到一个新格子记录自己已经走过的方向&am…

技术阅读周刊第第8️⃣期

技术阅读周刊,每周更新。 历史更新 20231103:第四期20231107:第五期20231117:第六期20231124:第七期 Prometheus vs. VictoriaMetrics (VM) | Last9 URL: https://last9.io/blog/prometheus-vs-victoriametrics/?refd…

微服务1 springcloud学习笔记P1-P40

b微服务技术栈_哔哩哔哩_bilibili 文档资料: 链接:https://pan.baidu.com/s/1P_Ag1BYiPaF52EI19A0YRw?pwdd03r 提取码:d03r 一 了解微服务技术 二 Eureka (1) Eureka配置 (2) 注册user-service (3) 总结 Ribbon 负载均衡 (1) 流程 三 nacos配置管理…

26、pytest使用allure解读

官方实例 # content of pytest_quick_start_test.py import allurepytestmark [allure.epic("My first epic"), allure.feature("Quick start feature")]allure.id(1) allure.story("Simple story") allure.title("test_allure_simple_te…

MySQL_2.常用维护命令

(1)查看数据库版本 show variables like %version%; (2)数据库信息 列出所有的数据库 show databases; 切换数据库 use <database_name>; 查看数据库信息 show databases <database_name>; 查看当前使用数据库 …

百度Apollo新版本Beta技术沙龙参会体验

在自动驾驶领域&#xff0c;百度的Apollo一直是业界开源的标杆。其持续升级和创新的开源项目为整个自动驾驶行业树立了典范&#xff0c;不仅推动了技术的发展&#xff0c;也为广大的社区开发者们提供了学习和参考的范本。最近百度发布了Apollo新的Beta版本&#xff0c; 新版本B…

根文件系统初步测试

一. 简介 上一篇文章学习了向所编译生成的根文件系统中加入 lib库文件。文章地址如下&#xff1a; 根文件系统lib库添加与初步测试-CSDN博客 本文继上一篇文章的学习&#xff0c;本文对之前制作的根文件系统进行一次初步测试。 二. 根文件系统初步测试 为了方便测试&#…

Unity3D实现鼠标悬浮UI或物体上显示文字信息

系列文章目录 Unity工具 文章目录 系列文章目录前言最终效果一、UI事件显示文字1-1 ui事件需要引用命名空间using UnityEngine.EventSystems;1-2 IPointerEnterHandler 接口1-3 IPointerExitHandler 接口1-4 IPointerMoveHandler 接口 二、场景搭建2-1 实现如下 三、代码实现3…

Windows11亮度调节滑块消失不见,如何解决

电脑亮度调节滑块消失&#xff0c;键盘F6&#xff0c;F7亮度调节失效&#xff0c;系统-屏幕-亮度和颜色-亮度调节消失不见 1.首先winR ,输入regedit打开注册表编辑器 2.在注册表编辑器中依次点击(红橙黄绿青蓝紫) “计算机\HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Cl…

Linux edquota命令教程:如何管理用户和组的磁盘配额(附案例详解和注意事项)

Linux edquota命令介绍 edquota命令在Linux中用于编辑用户或组的配额。配额用于限制用户或组可以消耗的文件系统空间。edquota命令打开一个文本编辑器&#xff0c;通常是vi&#xff0c;允许用户编辑指定用户或组的配额信息。 Linux edquota命令适用的Linux版本 edquota命令在…

政府信息化与电子政务

前言&#xff1a;各个地方的省级政务服务平台是最具代表性的政务服务领域。 1、数字政府和政府服务的概念区别 数字政府 数字政府是指以新一代信息技术为支撑&#xff0c;重塑政务信息化管理架构、业务架构、技术架构&#xff0c;通过构建大数据驱动的政务新机制、新平台、新渠…

班级查分软件制作教程:老师必备技能!

首先&#xff0c;你需要选择一个合适的软件平台来制作班级查分软件。推荐使用群发成绩&#xff0c;因为它是一个功能强大且易于使用的在线查询系统&#xff0c;可以帮助你快速高效地制作班级查分软件​。 在制作班级查分软件之前&#xff0c;你需要准备好学生的成绩数据。这可以…

如何选择Docker基础镜像

镜像官网 操作系统基础镜像 busybox Alpine CentOS Ubuntu Debian 编程语言基础镜像 Java基础镜像 Python基础镜像 NodeJs基础镜像 应用基础镜像 Nginx基础镜像 Tomcat基础镜像 Jetty基础镜像 其它基础镜像例子 Maven基础镜像 Jenkins基础镜像 GitLab基础镜像 如何选择Docker基…

量化学习笔记——入门与基本概念

基本概念 量化投资 投资的核心是大数定律。 量化投资就是以数据为基础&#xff0c;以策略模型为核心&#xff0c;以程序化交易为手段&#xff0c;以 追求绝对收益为目标 的投资方法。 用数学表示金融市场&#xff0c;其数学定义&#xff1a; Y F ( x 1 , x 2 , . . . . .…

Java 连接Sqlite数据库

POM文件添加依赖 <dependency><groupId>org.xerial</groupId><artifactId>sqlite-jdbc</artifactId><version>3.36.0.3</version></dependency> application.yml spring:datasource:#url: jdbc:sqlite::resource:db/main.db…

python 0 or 1为什么返回1,or运算原理

0 or 1的python表达式为什么返回1 首先&#xff0c;应该先搞清楚or的用法&#xff0c;在逻辑or的比较运算中&#xff0c;比如m or n中&#xff0c;Python会先对m进行bool布尔运算bool(m)&#xff0c;如果返回True&#xff0c;则m or n的返回值为m&#xff0c;如果返回False&am…

备战春招——12.05算法

树、二叉树 本次主要是对树、二叉树的前中后和递归与非递归遍历以及通过这种结构完成一些操作实现。 二叉树 中序遍历 中序遍历就是中间打印出结果嘛,如下列递归实现的&#xff0c;中间取结果. /** 递归实现* Definition for a binary tree node.* struct TreeNode {* …