【C语言】volatile 防止编译的时候被优化

volatile 易变的
volatile是 C 和 C++ 中的一个类型修饰符,用于指示编译器该变量可能在程序之外被更改,因此不应对其进行优化。这在涉及硬件寄存器、信号处理或多线程编程时非常有用。

如果你做过单片机开发,你肯定写过这样的代码:延时函数。就是通过循环延长CPU的时间,常见于流水灯、蜂鸣器这些对时间精度要求不高的地方,但是这样的代码却存在着很严重的缺陷,如果编译的过程中开启了优化,有些编译器会认为这几行代码是废话,什么事情也没干,在寄存器中会跳过这部分代码。

于是,在C语言中有了一个很重要的关键字volatile,它的作用是防止编译的时候被优化,在变量之前加上volatile,编译的时候即便开启最高等级的优化gcc test.c -o test -03,原代码中的编译将不再遭到优化处理。volatile在嵌入式开发中非常的重要而且常用,尤其是操作硬件或者多线程的场景。因为编译器在很多时候为了提升程序的运行效率,会跳过和优化掉一些没用的代码,或者直接从寄存器中或者缓存中读取某些变量的值,因为从寄存器或者缓存中取值速度要比内存快,如果这个变量是个共享数据,或者有可能被中断等程序修改,那么,我们读取到的数据就有可能跟内存中的数据不一致。如果在编译中发生这样的事,接下来程序执行的过程中就会导致一系列的问题。

请添加图片描述
请添加图片描述

int a = 10; // 在内存占用4个字节空间,该空间取名为a,cpu将10存入内存a空间中int b = a;  // 在内存占用4个字节空间,该空间取名为b,cpu将内存a的值取出来,保存在cpu寄存器中(寄存器a)// 将寄存器a 赋值给 内存b空间 
int c = a;  // 在内存占用4个字节空间,该空间取名为c,将寄存器a 赋值给 内存c空间
int d = a;  // 在内存占用4个字节空间,该空间取名为d,将寄存器a 赋值给 内存d空间
int e = a;  // 在内存占用4个字节空间,该空间取名为e,将寄存器a 赋值给 内存e空间// 假如 在int c = a的时候,不惊动cpu 去修改了内存中a的值,那么我们期望 d 和 e 的值 要和修改后a 的值 一致
// 但是 d 和 e 中依旧存入的是在 寄存器a 的值,造成 d 和 e 的值达不到我们的期望 // 更改方式:(初始化 int a 更改为 volatile)
volatile int a = 10;  //防止CPU对a变量进行优化,从此以后只要用到a的值,就必须去内存中重新读取  —— 每次必须区内存中拿,不去CPU中拿

加上volatile就是告诉编译器这个变量是不稳定的,无论编译器怎么优化,每次都得从内存中去读取,

请添加图片描述

volatile的用途:

  • 硬件寄存器访问:
    • 直接访问:确保每次访问硬件寄存器时都使用 volatile,以避免编译器优化。因为访问硬件设备的寄存器时,寄存器的值可能会在程序之外改变。
	volatile uint32_t *timer_register = (uint32_t *)0x40000000;*timer_register = 0x01;
  • 信号处理/中断处理:
    • 标志变量:将中断服务程序(ISR)中使用的标志变量声明为 volatile。
    • 在信号处理程序中使用的变量,因为信号可以在任何时候中断程序执行。
	volatile int interrupt_flag = 0;void ISR_Handler() {interrupt_flag = 1;}
  • 多线程和共享变量:
    • 共享状态:在多线程应用中,声明那些在不同线程间共享且不受锁保护的变量为 volatile。
    • 在多线程环境中,一个线程可能会修改另一个线程正在读取的变量。
	volatile bool data_ready = false;

示例:

	#include <stdint.h>#include <stdbool.h>volatile bool data_ready = false;volatile uint32_t *adc_result = (uint32_t *)0x40001000;void ADC_ISR() {*adc_result = // 读取ADC值data_ready = true;}int main() {while (1) {if (data_ready) {// 处理ADC结果data_ready = false;}}return 0;}

通过正确使用 volatile,可以确保嵌入式系统中硬件和软件的正确交互。

简单的说,volatile 是禁止编译器对该变量的访问进行优化(如缓存、寄存器存储),每次访问该变量时,都会从内存中读取或写入。


使用的时候需要注意的事项:

  1. 仅用于必要情况:不要滥用volatile,只在有硬件交互或异步变化时使用。
  2. 结合同步机制:volatile不能替代互斥锁、信号量等同步机制,需要与其他同步机制(如互斥锁、原子操作)结合使用以确保多线程安全。
  3. 读写原子性:volatile不能保证读写操作的原子性,需要时使用原子操作或禁用中断。
  4. volatile 不能保证线程安全,它仅防止编译器优化。

以上。

我是一个十分热爱技术的程序员,希望这篇文章能够对您有帮助,也希望认识更多热爱程序开发的小伙伴。
感谢!

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

makefile速通

makefile速通 文章目录 makefile速通1.基础显式规则隐含规则%*通配符 赋值 伪目标CFLAGS 2.函数wildcardpatsubst 3.项目实例 1.基础 显式规则 目标文件&#xff1a;依赖文件 [TAB] 指令隐含规则 % 任意* 所有通配符 符号含义$^所有依赖文件$所有目标文件$<所有依赖文…

面向服务的软件工程——巨详细讲解商务流程建模符号 (BPMN),一篇章带你入门BPMN!!!(week1)

文章目录 一、前言二、重点概念三、BPMN元素讲解流对象1.活动任务(Task)子流程(sub-process)多实例活动连接对象序列流消息流关联泳道Artifacts数据对象组(Group)事件(Events)启动事件中间事件结束事件边界事件边界事件1边界事件2小疑问?网关参考文献:一、前言 在我们…

模拟实现~简易通讯录

一.前言 今天给小伙伴们分享的是运用结构体以及指针等相关C语言知识实现一个简易版的通讯录。咱们写的通讯录的功能主要包括添加及删除联系人&#xff0c;修改联系人信息&#xff0c;显现所有联系人&#xff0c;查找已添加联系人&#xff0c;以及对联系人进行排序&#xff0c;…

0成本添加访问级监控

互联网的安全感这个概念源于阿里。顾名思义&#xff0c;让互联网的用户对于web产品能够产生足够的信任和依赖。特别是涉及到用户资金交易的站点&#xff0c;一次严重的用户资料泄露就可以彻底毁掉你的品牌。 然而当前阶段除了bat大部分互联网行业的企业对于网络安全给的重视都…

分布式系统稳定性建设-性能优化篇

分布式系统稳定性建设-性能优化篇 系统稳定性建设是系统工程的核心内容之一。以下是一些重要的方面: 架构设计: 采用模块化、松耦合的架构设计,以提高系统的可扩展性和可维护性。合理划分系统功能模块,降低单个模块的复杂度。定义清晰的接口和数据交换标准,确保各模块之间协调…

Web端高效BIM 3D可视化引擎HOOPS Communicator技术解析!

HOOPS Communicator是一款简单而强大的工业级高性能3D Web可视化开发包&#xff0c;专注于Web端工程图形渲染。采用了先进的流式加载方式&#xff0c;并支持服务端和客户端渲染&#xff0c;是可以在云端进行部署和无缝集成的新技术平台。 灵活且易于部署&#xff0c;可在以工程…

C/C++实现tcp客户端和服务端的实现(从零开始写自己的高性能服务器)

目录 tcp客户端通信流程 tcp客户端设计 1、创建通信对象 2、链接服务器 3、发送数据 / 读取数据 4、关闭通信 tcp服务端设计 1、创建通信对象 2、绑定服务器地址信息 3、设置服务器为监听模式 4、接收客户的链接请求 编写tcp客户端和服务端&#xff0c;实现双向通信…

C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程

引言 C 标准模板库&#xff08;STL&#xff09;提供了一组功能强大的容器类&#xff0c;用于存储和操作数据集合。不同的容器具有独特的特性和应用场景&#xff0c;因此选择合适的容器对于程序的性能和代码的可读性至关重要。对于刚接触 C 的开发者来说&#xff0c;了解这些容…

快速上手并使用Muduo库

Muduo muduo库是基于主从reactor模型的高性能服务器&#xff08;高并发服务器&#xff09;框架 reactor模型&#xff1a;基于事件触发的模型&#xff08;基于epoll进行IP事件监控&#xff09; 主从reactor模型&#xff1a;将IO事件监控有进行进一步的层次划分 主reactor&#x…

深入解析【C++多态】:探索面向对象编程中的动态绑定与行为多样性和多态的核心概念与应用实践

&#x1f31f;个人主页&#xff1a;落叶 &#x1f31f;当前专栏: C专栏 目录 多态的概念 多态的定义及实现 实现多态还有两个必须重要条件 虚函数 虚函数的重写/覆盖 多态场景的⼀个选择题 虚函数重写的⼀些其他问题 协变(了解进行) 析构函数的重写 override 和 final关…

React Native Mac 环境搭建

下载 Mac 版Android Studio 下载 安装 JDK 环境 Flutter 项目实战-环境变量配置一 安装 Node.js 方式一 通过Node.js 官网下载 下载完成后点击安装包进行安装 安装完成

【Word】一键批量引用论文上标——将正文字体改为上标格式

【Word】一键批量引用论文上标——将正文字体改为上标格式 写在最前面Word一键批量引用论文上标技巧分享核心思路&#xff1a;Word 替换功能 通配符步骤详解1. 打开 Word 替换功能2. 输入通配符模式3. 设置替换格式为上标4. 批量替换 实际效果展示技巧扩展 &#x1f308;你好呀…

深入探索Python数据可视化:自定义颜色映射、标签与进阶技巧

目录 一、自定义颜色映射&#xff08;Cmap&#xff09; 1. 内置Cmap类型 2. 使用内置Cmap 3. 自定义Cmap 二、标签添加 1. 在散点图上添加标签 2. 在折线图上标记关键点 3. 在柱状图上添加标签 三、进阶技巧 1. 多图形布局 2. 添加图例 3. 3D数据可视化 四、总结 …

【Java SE】数据库连接池

数据库连接池是一个管理数据库连接的容器。它的主要作用是分配和管理数据库连接&#xff0c;允许应用程序重复使用现有的连接&#xff0c;而不是每次都重新建立新的连接。此外&#xff0c;连接池会释放那些空闲时间超过最大限制的连接&#xff0c;从而避免因未及时释放连接而造…

FastAPI重载不生效?解决PyCharm中Uvicorn无法重载/重载缓慢的终极方法!

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 重载缓慢 📒📝 问题概述🚨 相关原因📝 解决方案一📝 解决方案二📝 解决方案三📝 解决方案四⚓️ 相关链接 ⚓️📖 介绍 📖 在使用FastAPI开发时,reload=True 本应让你在修改代码后自动重启服务,提升开发效率…

CPU算法分析LiteAIServer视频智能分析平台未戴安全帽检测算法

随着人工智能技术的不断进步&#xff0c;CPU算法分析在视频智能分析平台中的应用日益广泛。特别是在工地安全管理领域&#xff0c;未戴安全帽检测算法已成为一项关键的安全保障措施。LiteAIServer视频智能分析平台通过结合CPU的高效运算能力和先进的深度学习算法&#xff0c;实…

两网站定时数据exchange项目详解

功能说明 A网站&#xff1a;用户可以通过表单输入嫌疑人信息&#xff0c;这些信息会被存储在内存中&#xff0c;并通过API接口返回。B网站&#xff1a;通过API接口接收从A网站同步过来的嫌疑人数据&#xff0c;并显示这些数据。主应用&#xff1a;使用APScheduler每隔1分钟从A…

【云计算】腾讯云架构高级工程师认证TCP--考纲例题,知识点总结

【云计算】腾讯云架构高级工程师认证TCCP–知识点总结&#xff0c;排版整理 文章目录 1、云计算架构概论1.1 五大版块知识点&#xff08;架构设计&#xff0c;基础服务&#xff0c;高阶技术&#xff0c;安全&#xff0c;上云&#xff09;1.2 课程详细目录1.3 云基础架构设计1.4…

sql server查看当前正在执行的sql

#统计某类sql执行次数&#xff0c;并按总体cpu消耗时间降序排序 with a as ( select er.session_id,db_name(er.database_id) as DBNAME,sy.last_batch AS 最后执行时间, er.cpu_time ,er.total_elapsed_time/1000 as sum_elapsed_time_s, CAST(csql.text AS varchar(8000)) A…

【UE5】Slider控件样式

实现根据滑柄位置确定滑条样式的功能&#xff0c;效果如下。 效果 步骤 1. 添加Slider控件和文本控件&#xff0c;其中文本控件用于显示滑条的值 2. 文本控件绑定变量&#xff0c;这里变量为“Year” 3. 当滑条的值变更后&#xff0c;设置“Year”的值&#xff0c;然后调用函…