volatile详解(任何人都能懂的那种)

2023-10-27

volatile

看了好多篇博客终于明白这个关键字到底是干嘛的…让我综合所有的博客写一篇大家都能理解它的博客,要点赞呦!!!

volatile是一个类型修饰符,作用是作为指令关键字,一般都是和const对应,确保本条指令不会被编译器的优化而忽略。

先从一个简单的栗子说起吧
看下面一段代码 (选择题中会考!!!)

int main()
{
	int i = 10;
	int a = i;

	printf("%d", i);

	//下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道
	__asm
	{
		mov dword ptr[ebp - 4], 20h
	}
	int b = i;
	printf("i=%d", b);
	return 0;
}

然后,在debug(调试)版本模式运行程序,输出结果如下:

i = 10
i = 32

然后在release版本模式运行下,输出结果如下:

i = 10
i = 10

输出结果表明一个问题,在release模式下,编译器对代码进行了优化,具体优化结果如下:
由于编译器发现两次从 i读数据的代码之间的代码没有对 i 进行过操作,它会自动把上次读的数据放在 b 中。而不是重新从 i 里面读。这样以来,如果 i是一个寄存器变量或者表示一个端口数据就容易出错

下面,我们把i的声明加上关键字volatile,看看有什么变化没

int main()
{
	volatile int i = 10;
	int a = i;

	printf("%d", i);

	//下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道
	__asm
	{
		mov dword ptr[ebp - 4], 20h
	}
	int b = i;
	printf("i=%d", b);
	return 0;
}

分别在debug和release版本运行结果都是如下:

i = 10
i = 32

这说明volatile发挥了它的作用。

这时,我们在配合一个例子再次深入理解一下

发薪资时,会计每次都把员工叫来登记他们的银行卡号;一次会计为了省事,没有即时登记,用了以前登记的银行卡号;刚好一个员工的银行卡丢了,已挂失该银行卡号;从而造成该员工领不到工资

员工 -- 原始变量地址

银行卡号 -- 原始变量在寄存器的备份

volatile应该解释为“直接存取原始内存地址”比较合适,“易变的”这种解释简直有点误导人;

精华!!!!(一定要看)

  • volatile对应的变量可能在你的程序本身不知道的情况下发生改变
  • 比如多线程的程序,共同访问的内存当中,多个程序都可以操纵这个变量
  • 你自己的程序,是无法判定何时这个变量会发生变化
  • 还比如,他和一个外部设备的某个状态对应,当外部设备发生操作的时候,通过驱动程序和中断事件,系统改变了这个变量的数值,而你的程序并不知道。
  • 对于volatile类型的变量,系统每次用到他的时候都是直接从对应的内存当中提取,**而不会利用cache当中的原有数值,**以适应它的未知何时会发生的变化,系统对这种变量的处理不会做优化——显然也是因为它的数值随时都可能变化的情况。

让我们举几个volatile的例子

1)并行设备的硬件寄存器(如:状态寄存器)
2)一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3)多线程应用中被几个任务共享的变量

面试小题

1)一个参数既可以是const还可以是volatile吗?解释为什么。

是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。

2)一个指针可以是volatile 吗?解释为什么。

是的。尽管这并不很常见。一个例子是当一个中断服务子程序修改一个指向一个buffer的指针时。

3)下面的函数被用来计算某个整数的平方,它能实现预期设计目标吗?如果不能,试回答存在什么问题:

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;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

volatile详解(任何人都能懂的那种) 的相关文章

  • python基于图像颜色的火焰识别

    本文基于图像颜色 主要结合RGB和HSI两种判断依据进行火焰识别 判断依据参考了以下文章 实在是非常感谢 OpenCV学习记录之视频中的火焰检测识别 python版基于颜色的火焰识别 判断条件如下 R gt redThre R gt G g
  • 数据竞赛专题

    为了帮助更多竞赛选手入门进阶比赛 通过数据竞赛提升理论实践能力和团队协作能力 DataFountain 和 Datawhale 联合邀请了数据挖掘 CV NLP领域多位竞赛大咖 将从赛题理解 数据探索 数据预处理 特征工程 模型建立与参数调
  • mmcv读取配置文件,在windows上无法创建临时文件解决方法

    报错是写入 盘的Temp没有权限 因此修改到其他目录 在config中修改以下两个函数 def substitute predefined vars filename temp config name file dirname osp di
  • 用工厂模式管理多个solidity智能合约

    我们写了一份小的计算合约作为Hello World 如果我们可以创建一个允许用户创建自己的计数器的合约怎么办 让我们创建我们的合约CounterFactory 它将管理所有其他计数器Counters 它将包含一个映射 将所有者与其计数器合约
  • captcha验证码入门

    kaptcha是一个简单易用的验证码生成工具 而且支持中文 你还可以配置其很多属性 用法 1 首先到http code google com p kaptcha downloads list把压缩文件下下来 然后把里面的jar文件加到自己的
  • 项目一:用OpenCV识别银行卡号

    import cv2 def sort contours cnts method left to right reverse False i 0 if method right to left or method bottom to top
  • 阿里巴巴的数据库连接池 druid 优点

    阿里的 druid 它不仅仅是一个数据库连接池 它还包含一个ProxyDriver 一系列内置的JDBC组件库 一个SQL Parser Druid 相对于其他数据库连接池的优点 1 强大的监控特性 通过Druid提供的监控功能 可以清楚知
  • 凯恩帝数控系统面板介绍_凯恩帝数控车床操作面板按钮详解!

    KND1TB数控系统操作 在 视图 下拉菜单或者浮动菜单中选择 控制面板切换 后 数控系统操作键盘会出现在视窗的右上角 其左侧为数控系统显示屏 如下图所示 用操作键盘结合显示屏可以进行数控系统操作 KND1TB 输入面板 按键介绍 数字键
  • 黑苹果系统--Parallels Desktop虚拟机使用

    1 挂载外部磁盘到windows虚拟机 1 通过USB将外部磁盘连接至Mac 2 在虚拟机配置窗口中 选择 Hardware gt Add gt Hard Disk 3 在 Type 菜单中选择 Physical Disk 并在 Locat
  • Linux EOIP — 二层协议

    一 协议介绍 EOIP是一个 MikroTik的 Linux使用 TAP的 EoIP EoIPv6隧道的实现 EoIP Ethernet over IP 和 EoIPv6 Ethernet over IPv6 是 MikroTik Rout
  • MATLAB---同态滤波

    同态滤波 clc clear close all 清理命令区 清理工作区 关闭显示图形 warning off 消除警告 feature jit off 加速代码运行 tic filename pathname uigetfile bmp
  • 如何确定自己的科研课题?

    许多研究生刚入学的时候对科研都是一头雾水 不知道文献如何检索 不知道科研该如何发展 总有一段很长的时间在惆怅着我究竟该做些什么 而在写科研论文 确定科研选题就是第一步 那么 到底如何才能确定自己的科研课题呢 本文主要为大家分享以下三点 选题
  • 手把手_下载与安装Ubuntu_18.04_Linux系统

    1 下载Ubuntu镜像文件 1 找到官网 Ubuntu官网 注 不想了解官网的 请直接跳到清华镜像网 2 找到下载入口 如果您要下载最新版本的系统 就直接点击download 1 但是本文以18 04版本为例 故此 点击2处 3 找到国内
  • Python(7)

    Python 7 目录 Python 7 函数 全局变量与局部变量 文件 错误与异常 finally 函数 python的函数使用def定义 def add a b return a b def multiply a b return a
  • ESP8266连接 TCP

    AT GMR查看固件版本 v1 0以上固件命令如下 恢复到初始状态 AT RESTORE 设置WiFi应用模式为Station和Server共存模式 AT CWMODE 3 连接路由器 SSID为路由器用户名 Password为密码 AT
  • cocosCreator 物理关节组件

    cocosCreator 物理关节组件 重点 距离关节 旋转关节 绳子关节 轮子关节 焊接关节 棱柱关节 马达关节 重点 开启物理系统 物理系统默认是关闭的 如果需要使用物理系统 那么首先需要做的事情就是开启物理系统 否则你在编辑器里做的所
  • 如何在WPS、Word里插入高亮代码块

    需要使用Notepad step1 我们首先需要在Notepad 里安装好NppExport插件 步骤如下 第1步 打开 插件管理 第2步 搜索并安装 NppExport 插件 安装后 在已安装界面如下图所示 step2 然后将代码复制在N
  • ws协议与http协议的异同_websocket和http的区别

    websocket和http的区别 1 WebSocket是双向通信协议 模拟Socket协议 可以双向发送或接受信息 而HTTP是单向的 2 WebSocket是需要浏览器和服务器握手进行建立连接的 而http是浏览器发起向服务器的连接
  • 企业运维经典面试题汇总(2)

    1 写一个脚本查找最后创建时间是三天前 后缀是 log的文件并删除 find ctime 3 name log rm rf 2 统计ip访问情况 要求分析nginx访问日志 找出访问页面数量在前十位的ip cat access log aw
  • IDEA-Docker配置CA证书和远程访问

    前言 为了优化idea docker部署 防止自己服务器端口2375被黑 这里简单介绍一下idea docker的ca证书配置 1 新建一个脚本docker ca sh 将下面的脚本复制进去 注意修改一下docker主机ip 创建 Dock

随机推荐

  • spring boot org.springframework.context.annotation.ConflictingBeanDefinitionException

    org springframework context annotation ConflictingBeanDefinitionException 分析接解决方法 错误信息 分析接解决方法 annotation ConflictingBea
  • [从零开始学DeepFaceLab-10]: 使用-命令行八大操作步骤-第6步:模型的选择与训练 - 模型训练

    目录 总体流程 步骤6 模型的选择与训练 模型训练命令 6 1 命令 6 train Quick96 bat 适用CPU only情形以及快速学习 必需之一
  • redis mysql 案例_redis 使用案例

    1 使用redis消息列队发布信息 在一些用户创造用户的应用中 如SNS 微博 可能出现1秒有上千万个用户同时发布消息的情况 此时如果使用mysql可能出现 too many connections 错误 当然 把mysql的max con
  • idea java 远程调试_使用IDEA进行JAVA代码的远程Debug

    在本地开发过程中 对代码进行Debug能逐行对代码逻辑进行调试 方便准备的排查问题 但是当代码发布到线上时 如果运行过程中出现异常 仅仅依靠日志来排查问题的话 会比较耗时 而且经常由于日志不全等原因而不能快速准确定位问题 而通过对JAVA代
  • 电机控制基础——定时器基础知识与PWM输出原理

    单片机开发中 电机的控制与定时器有着密不可分的关系 无论是直流电机 步进电机还是舵机 都会用到定时器 比如最常用的有刷直流电机 会使用定时器产生PWM波来调节转速 通过定时器的正交编码器接口来测量转速等 本篇先介绍定时器的基础知识 然后对照
  • importing maven projects 9% 卡住

    导入一个maven工程后 一直显示 importing maven projects 9 解决办法 找到eclipse安装目录下的eclipse ini 在最后加入 vm JAVA HOME bin javaw exe 再次重启eclips
  • flutter 环形进度条组件CircularProgressIndicator、线性进度条组件LinearProgressIndicator

    环形进度条组件 不能放在ListView中 若不设置value 即无value参数 会一直加载动画 LinearProgressIndicator valueColor AlwaysStoppedAnimation Colors x 设置进
  • 如何进入mysql命令界面

    1 找到安装mysql安装路径 复制bin目录地址 eg D installmysqlin 2 进入cmd命令窗口 3 因为安装到D盘 进入D盘的盘符 输入D 直接输入cdD installmysqlin是无效的 4 进入bin目录 cdD
  • video.js 播放 rtsp、hls

    什么是HLS RTSP RTMP HLS HTTP Live Streaming 苹果公司提出的流媒体协议 直接把流媒体切片成一段段 信息保存到m3u列表文件中 可以将不同速率的版本切成相应的片 播放器可以直接使用http协议请求流数据 可
  • arduino+esp8266+onenet+mqtt_4G模块(EC20)连接MQTT服务器(EMQ X)

    上面的示意图也是这篇推文的主题 使用三个客户端EC20 ESP8266 MQTTX通过MQTT协议连接上我们搭建的EMQ X服务器最后完成消息的发布和订阅 概述 其中ESP826大家都有认识 那么相对陌生的EC20是一个4G模块 MQTTX
  • vika+obsidian快速进入一个研究领域

    目的是快速熟悉一个陌生的研究领域 写出文献综述 步骤 检索相关文献100篇以上 在vika中建表格 表头如下所示 阅读100篇论文的题目 关键词 摘要 填充vika表格 并找出需要精度的文献10篇左右 中文综述优先 精度10篇论文 并用ob
  • 《程序员面试宝典》第6章 宏和const

    一 用一个宏定义FIND求一个结构体struc里某个变量相对struc的偏移量 int a char b 20 double cc FIND student a 0 FIND student b 4 FIND student cc 4 20
  • vscode 如何自动补全react和jsx代码?

    补全react代码 文件 首选项 设置 打开之后 搜索emmet includeLanguages 添加javascript javascriptreact属性 重启即可生效 补全jsx代码 在原来的搜索位置 搜索emmet trigger
  • 《游戏测试精通》观后感

    第I部分 游戏测试简介 第一章 游戏测试的两条原则 1 不要恐慌 2 不要相信任何人 在第一章第一节的学习中 我了解到了 作为一名测试工作者 不论是不是新手还是一个资深的 老人 在处于以下场景时 都会或多或少的出现恐慌的情况 不熟悉环境或业
  • PCI-E

    PCI E 1 简介 PCI E PCI Express的所写 是最新的总线和接口标准 它原来的名称为 3GIO 是由英特尔提出的 很明显英特尔的意思是它代表着下一代I O接口标准 交由PCI SIG PCI特殊兴趣组织 认证发布后才改名为
  • 1. 两数之和 C++

    给定一个整数数组 nums 和一个整数目标值 target 请你在该数组中找出 和为目标值 target 的那 两个 整数 并返回它们的数组下标 你可以假设每种输入只会对应一个答案 但是 数组中同一个元素在答案里不能重复出现 你可以按任意顺
  • 一文搞懂OC门、OD门及其作用

    我们先给出OC门 OD门的定义 然后从原理出发 介绍OC门 OD门的作用 1 什么是OC门 OD门 OC门 Open Collector Gate 集电极开路门 如图1所示 当N1导通时 输出低电平 当N1截止时 输出高阻态 电路的一种输出
  • 火狐安装网页视频下载插件(Video DownloadHelper)

    Video DownloadHelper是一款以最简单的方式下载网页视频的chrome插件 基本上火狐浏览器能够加载出视频流并正常播放的视频该插件都能够抓取 可以说该插件对于网页视频下载还是十分快捷并且使用场景广泛的 本地安装后的版本 Vi
  • 字节数组的妙用

    在计算机高级语言中 字节属于最小单位 例如在Java中 int占用4个字节 long占用8个字节等 基本上所有基本类型 包括String 都可以转换成字节 那么这到底有何作用 本篇博客主要是记录了我使用字节数组的经验 希望可以给大家提供一些
  • volatile详解(任何人都能懂的那种)

    volatile 看了好多篇博客终于明白这个关键字到底是干嘛的 让我综合所有的博客写一篇大家都能理解它的博客 要点赞呦 volatile是一个类型修饰符 作用是作为指令关键字 一般都是和const对应 确保本条指令不会被编译器的优化而忽略