C语言:volatile关键字讲解

 

读音:vaoletail

   C语言中的volatile关键字是一个重要的类型修饰符,它用于声明一个变量具有“易变性”,即可能在编译器无法察觉的情况下被改变其值。Volatile意思是“易变的”,应该解释为“直接存取原始内存地址”比较合适。 “易变”是因为外在因素引起的,像多线程,中断等。

    volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,告诉编译器对该变量不做优化,都会直接从变量内存地址中读取数据,从而可以提供对特殊地址的稳定访问。

    如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。

总结:volatile关键词影响编译器编译的结果,用volatile声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不要进行编译优化,以免出错。

编译器优化介绍:

  由于内存访问速度远不及CPU处理速度,为提高机器整体性能。

1)在硬件上:  引入硬件高速缓存Cache,加速对内存的访问。另外在现代CPU中指令的执行并不一定严格按照顺序执行,没有相关性的指令可以乱序执行,以充分利用CPU的指令流水线,提高执行速度。

2)软件一级的优化:一种是在编写代码时由程序员优化,另一种是由编译器进行优化。编译器优化常用的方法有:将内存变量缓存到寄存器。

由于访问寄存器要比访问内存单元快的多,编译器在存取变量时,为提高存取速度,编译器优化有时会先把变量读取到一个寄存器中;以后再取变量值时就直接从寄存器中取值。但在很多情况下会读取到脏数据,严重影响程序的运行效果。

一般说来,volatile用在如下的几个地方: 
(1)中断服务程序中修改的供其它程序检测的变量,需要加volatile:当变量在触发某中断程序中修改,而编译器判断主函数里面没有修改该变量,因此可能只执行一次从内存到某寄存器的读操作,而后每次只会从该寄存器中读取变量副本,使得中断程序的操作被短路。
 (2)多线程环境:在多线程编程中,如果多个线程共享并修改某个变量,而该变量的改变不受当前执行线程控制(比如由其他线程、中断服务程序或者硬件本身修改),那么这个变量就应该用volatile来修饰,以保证所有线程都能看到最新更新的值。
(3)硬件访问:与硬件交互时,例如访问状态寄存器或其他硬件映射的内存位置,这些位置的内容可能由硬件设备自行更改,而不通过CPU指令直接操作。在这种情况下,硬件寄存器通常需要被声明为volatile,这样每次访问都会得到最新的硬件状态,而非缓存在寄存器中的旧值。

注意:频繁地使用volatile很可能会增加代码尺寸和降低性能,因此要合理的使用volatile。


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

      一个函数参数可以同时被声明const和volatile。当一个参数既被声明为const又为volatile时,它意味着该参数在函数执行期间不可被修改(通过该函数),但其值可能在任何时间点被硬件、操作系统或其他并发线程等不受当前程序控制的因素改变。

例如,在嵌入式系统中,一个指向设备状态寄存器的指针作为函数参数时,它可以被声明为volatile类型。

void checkDeviceStatus(volatile const uint32_t* statusRegister)
{
    // 在此函数中,我们不能修改statusRegister指向的内容
    // 但是我们必须每次都从内存中读取它的实际值,因为它可能随时由外部硬件更改。
    if (*statusRegister & DEVICE_STATUS_FLAG) {
        // 处理设备状态
    }
}

volatile关键字确保编译器不会对statusRegister的内容进行优化,即使多次读取也会每次都直接从内存中读取;而const关键字则禁止函数体内部尝试修改这个寄存器的内容。


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

 一个指针不仅可以是volatile,而且在某些情况下必须这样声明。声明为volatile的指针表示其指向的数据可能会被程序外部因素异步更改,即使没有显式的修改语句。

例如,在多线程环境或与硬件交互的场合,某个全局变量可能是通过一个I/O端口或者中断服务程序来更新的,那么指向这个变量的指针就应该声明为volatile。

volatile int *portValue = (volatile int*)0x1000; // 假设0x1000是硬件端口地址

// 线程A中读取并处理端口值
while (1) {
    process(*portValue);
}

// 线程B中或中断服务例程中端口值被硬件改写
ISR() {
    *portValue = readHardwarePort();
}

volatile修饰符告诉编译器不要对portValue指向的内存位置进行优化,每次访问都需要重新读取内存中的实际值,因为硬件可能会在任何时候更新这个值。

????这个部分没看懂。
 


int main(void){
    int i;
    i = 1;
    i = 2;
    return i;
}

    在Debug模式(无任何优化)下, 生成的32位汇编代码(省略其它代码)为:

mov dword ptr[ebp-4],1
mov dword ptr[ebp-4],2
mov eax,dword ptr[ebp-4]
ret

        可见, 对i的每次赋值都会产生一条汇编语句来对应, 这完全同C程序意思,而当生成模式改成Release(优化被打开; 可能需要在项目设置中钩上"生成调试信息")后,对应如下(省略其它代码)。

mov eax,2
ret

多余的赋值代码都被优化掉了, 这就是编译器的优化措施。把源代码改成如下形式:

int main(void){
    volatile int i;
    i = 1;
    i = 2;
    return i;
}

    修改后, Debug生成的汇编代码没有变化, 但Release生成的代码却变成了:

        push ecx
        mov dword ptr[esp],1
        mov dword ptr[esp],2
        mov eax,dword ptr[esp]
        pop ecx

        可见, 加了volatile后, 就算打开优化, 编译器也不会作优化, 每次取值都是重新取值。


参考:

https://www.cnblogs.com/hjh-666/p/11148119.html

https://www.cnblogs.com/memset/archive/2012/12/19/2825530.html

https://www.cnblogs.com/armlinux/archive/2010/09/14/2396918.html

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【高质快刊】中科院1区TOP,最新案例仅2个月14天录用!进展超顺,即将截稿!

(一)期刊简介概况 【期刊类型】能源工程类SCIE&EI 【出版社】ELSEVIER出版社 【期刊概况】IF:11.0-12.0,JCR1区,中科院1区TOP 【预警情况】2020-2024年无预警记录 【收录年份】1977年被WOS数据库收录 【年发…

【python绘图colorbar对齐】

[Toc]# 1、问题描述 python在绘图过程中,可能会出现colorbar高度与主图不匹配情况,需要进行调整,使得与主图高度对齐,使图像更美观。示例:colorbar位置高于主图 2、解决方法 通过调整shrink参数匹配对齐,pad调整x轴…

【CPP】C++11多线程

thread类 在C11之前,涉及到多线程问题,都是和平台相关的,比如windows和linux下各有自己的接口,这使得代码的可移植性比较差。C11中最重要的特性就是对线程进行支持了,使得C在并行编程时不需要依赖第三方库&#xff0c…

ARM中断实验

key_inc.c #include"key_inc.h"void key1_it_config(){//使能GPIOF外设时钟RCC->MP_AHB4ENSETR | (0x1<<5);//将PF9设置为输入模式GPIOF->MODER & (~(0x3<<18));//设置由PF9管脚产生EXTI9事件EXTI->EXTICR3 & (~(0XFF<<8));EXTI-…

Linux-线程同步

文章目录 前言一、为什么要线程同步&#xff1f;二、线程同步pthread_cond_initpthread_cond_destroypthread_cond_wait、pthread_cond_signal和 pthread_cond_broadcast 三、示例代码 前言 上节课学习了线程互斥&#xff0c;这节课针对线程互斥内容在做进一步的补充和完善&am…

鸿蒙Harmony应用开发—ArkTS(@State装饰器:组件内状态)

State装饰的变量&#xff0c;或称为状态变量&#xff0c;一旦变量拥有了状态属性&#xff0c;就和自定义组件的渲染绑定起来。当状态改变时&#xff0c;UI会发生对应的渲染改变。 在状态变量相关装饰器中&#xff0c;State是最基础的&#xff0c;使变量拥有状态属性的装饰器&a…

Elasticsearch:让你的 Elasticsearch 索引与 Python 和 Google Cloud Platform 功能保持同步

作者&#xff1a;来自 Elastic Garson Elasticsearch 内的索引 (index) 是你可以将数据存储在文档中的位置。 在使用索引时&#xff0c;如果你使用的是动态数据集&#xff0c;数据可能会很快变旧。 为了避免此问题&#xff0c;你可以创建一个 Python 脚本来更新索引&#xff0…

VMWare虚拟机使用openmediavault搭建NAS服务器完整步聚

下载: gopenmediavault - The open network attached storage solution 下载好openmediavault的ISO镜像后,打开虚拟机并安装 系统类型选择Debian 启动虚拟机并安装openmediavault 选择中文 地区选中国 键盘配置选汉语 开始安装 配置网络信息 配置root密码 确认密码 系统安装中…

LeetCode # 199. 二叉树的右视图

199. 二叉树的右视图 题目 给定一个二叉树的 根节点 root&#xff0c;想象自己站在它的右侧&#xff0c;按照从顶部到底部的顺序&#xff0c;返回从右侧所能看到的节点值。 示例 1: 输入: [1,2,3,null,5,null,4] 输出: [1,3,4] 示例 2: 输入: [1,null,3] 输出: [1,3] 示例 3…

最新域名出售交易平台源码修复版

最新域名出售交易平台源码修复版 测试正常分享&#xff0c;保障你使用愉快&#xff0c;源码测试修复不易&#xff0c;拿走留痕是美德 无需到处找教程或修复&#xff0c;教程一次性到位&#xff0c;无需藏着掖着 最新修复版域名出售交易平台源码&#xff0c;搭建即可正常使用…

【群晖】Docker Compose部署 Emby Server

【群晖】Docker Compose部署 Emby Server 本来群晖上面的 Emby 是用套件安装的&#xff0c;但是不巧的是前两天脑袋一抽装了两个插件&#xff0c;导致 Emby Server被当肉鸡了&#xff0c;还找不到脚本代码在哪儿&#xff0c;一天时间上传了3T的流量。无奈之下&#xff0c;只能尝…

头条网盘拉新项目该怎么选择授权

作为十二月份首发上线的项目——头条网盘拉新。一经上线就受到很多想要做这行业人的关注&#xff0c;光是佣金已经是业内比较高的了&#xff01;每拉新一位新用户就可以获取到价格为9元一单的佣金&#xff0c;拉失活用户也可以获取价格为4元的佣金&#xff0c;推广方式和其他网…

真机笔记(2)项目分析

目录 1. 项目&#xff1a; 2. 网络工程师工作流程 3. 实验 设备命名 登录密码 使用SSH协议 1. 项目&#xff1a; 竞标方&#xff1a;集成商、厂商、代理商、服务商、监理检测公司 在一个网络项目中&#xff0c;不同的角色承担着不同的职责和任务。以下是集成商、厂商、代…

JavaScript-Web学习笔记01

一、Web APIs 1、Web API Web API 是浏览器提供的一套操作浏览器功能和页面元素的API&#xff08;BOM 和 DOM&#xff09;。 2、总结 API 是为我们提供的一个接口&#xff0c;帮助我们实现某种功能Web API 主要是针对浏览器提供的接口&#xff0c;主要针对浏览器做交互效果。W…

腾讯云COS - 前端上传文件到 COS 跨域问题

问题描述 原因分析 因为我本地的地址是&#xff1a;http://localhost:9528 而发送请求时的地址是&#xff1a;http://132-1307119153.cos.ap-beijing.myqcloud.com/tu.jpg 域名不同&#xff0c;自然而然就出现了跨域的问题&#xff01; 解决方案 先点击对象存储 - 安全设置…

吃瓜Grok大模型

段子区 今年当地时间2月29日晚&#xff0c;马斯克闹出来一件大事——正式起诉OpenAI和Sam Altman&#xff0c;并要求OpenAI 恢复开源GPT-4等模型。国际流量大师我只付服马斯克和川宝!&#xff01; 当大家觉得这扯皮的故事就此结束后&#xff0c;马斯克“不负众望”的整了一个大…

算法-图的强连通分量,图的最小生成树

1.图的强连通分量 (1). 定义 图的强连通分量是图论中的一个重要概念&#xff0c;主要在有向图中进行讨论。具体来说&#xff0c;如果在一个有向图G中&#xff0c;任意两个顶点vi和vj&#xff08;其中vi大于vj&#xff09;之间都存在一条从vi到vj的有向路径&#xff0c;同时也存…

解锁AI之门:协助探索Amazon Bedrock服务

AI愈加强大的功能和广泛的应用场景&#xff0c;正逐渐改变着我们的工作和生活方式。 Amazon Bedrock在AI的时代潮流中&#xff0c;也以其强大而灵活的功能特性&#xff0c;正在成为越来越多企业和个人的智能助手。 亚马逊云科技通过VERYCLOUD睿鸿股份的服务能力&#xff0c;使…

PyTorch深度学习:如何提升遥感影像的地物分类精度?

我国高分辨率对地观测系统重大专项已全面启动&#xff0c;高空间、高光谱、高时间分辨率和宽地面覆盖于一体的全球天空地一体化立体对地观测网逐步形成&#xff0c;将成为保障国家安全的基础性和战略性资源。未来10年全球每天获取的观测数据将超过10PB&#xff0c;遥感大数据时…

F. Microcycle(dfs 搜寻路径 + 并查集)

解析&#xff1a; 本题的意思是&#xff0c;求一个环的最小的那条边。 并且输出其这个环的点。 我们可以利用并查集&#xff0c;进行确定其是否有环路。在将所用的边从大到小排序。 利用 vector容器&#xff0c;pop_back() 和 push的特性。 起点为 u终点为 v寻找路径。 代…