【C语言】volatile关键字

目录

一、引入

二、volatile关键字

三、对编译器优化的理解


一、引入

我们先来看一段代码:

#include <stdio.h>
#include <signal.h>int flag = 1;void handler(int signo)
{flag = 0;printf("已收到%d号信号,flag:%d\n", signo, flag);
}int main()
{signal(2, handler);while (flag);printf("进程退出\n");return 0;
}

我们编译一下运行:

可以看到当我们按下Ctrl+c传给进程2号信号时,进程执行了handler方法将全局变量flag改成了0,while循环条件不为真,循环结束进程退出

没问题,结果也符合我们的预期

下面我们在gcc后面加上-O选项来看看:

-O 是 gcc 编译器的一个优化选项,用于告诉编译器进行优化以提高程序的执行效率。

选项 -O 后面可以跟一个数字,表示优化级别。常见的优化级别包括 -O0、-O1、-O2 和 -O3,数字越大表示优化级别越高。

 

咦?优化情况下,键入Ctrl+c,2号信号被捕捉,执行自定义动作,修改 flag=0 ,但是 while 条件依旧满足,进程继续运行!但是很明显flag肯定已经被修改了,但是为何循环依旧执行?这和我们逻辑上预期的结果并不一样啊?

下面我们来分析一下出现该情况的原因:

我们都知道while想要获取flag的值就必须将内存中存储的数据拿到CPU的寄存器当中:

但是在进程收到2号信号时,handler方法肯定将内存中的flag数据修改为0了,所以很明显,while 循环检查的flag, 并不是内存中最新的flag

这是因为编译器发现while循环体内并没有将flag的数据做任何修改,但是每一次循环将flag的数据拿到CPU中是IO操作,IO操作效率低下,因此在1/2/3的优化级别下,编译器将汇编代码的IO操作只进行一次,这样子后续的while循环直接从寄存器中拿数据即可

这就存在了数据二异性的问题。 while 检测的flag其实已经因为优化,被放在了 CPU寄存器当中。如何解决呢?

二、volatile关键字

C语言中的volatile关键字就可以解决上述问题,我们将全局变量flag前加上该关键字试试看:

#include<stdio.h>
#include<signal.h>volatile int flag=1;void handler(int signo)
{flag=0;printf("已收到%d号信号,flag:%d\n",signo,flag);
}int main()
{signal(2,handler);while(flag);printf("进程退出\n");return 0;
}

 在不同优化级别下的运行结果:

可以看到加上该关键字后,进程都成功退出了

所以该关键字的作用显然易见:

volatile 作用:保持内存的可见性,告知编译器,被该关键字修饰的变量,不允许被优化,对该变量的任何操作,都必须在真实的内存中进行操作 

三、对编译器优化的理解

我们从上述的例子中可以看出:编译器的优化本质上是对代码动手脚!

优化编译后的代码,确实可以提高程序的性能和执行效率。但是需要注意的是,在某些情况下,过高的优化级别可能会导致编译时间延长、代码变得难以调试或者得到错误的结果。因此,在选择优化级别时需要根据具体情况进行权衡。

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

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

相关文章

DIY耳机壳制作使用倒模UV树脂胶液对HIFI动铁音质有什么优势?

使用倒模UV树脂胶液制作DIY耳机壳并在HIFI动铁耳机上应用&#xff0c;可能会带来以下优势&#xff1a; 提高声音隔离度&#xff1a;UV树脂胶液可以有效地将动铁单元封装在耳机壳内&#xff0c;减少外界噪音的干扰&#xff0c;提高声音的隔离度。这有助于提高耳机的聆听体验&am…

紫微斗数双星组合:天同天梁在寅申

文章目录 前言内容总结 前言 紫微斗数双星组合&#xff1a;天同天梁在寅申 内容 紫微斗数双星组合&#xff1a;天同天梁在寅申 性格分析 天同星&#xff0c;天梁星入命宫&#xff0c;称做天同天梁坐命的人。其人外表温和&#xff0c;本性善良&#xff0c;但内心固执&#x…

蓝桥杯每日一题----单调栈和单调队列

单调栈和单调队列 单调栈 单调栈即栈内的元素是单调递减或者单调递增的&#xff0c;我们通过一个题目来理解。 单调栈模板题 题目描述 给出项数为 n 的整数数列 a 1 … a n a_1…a_n a1​…an​。 定义函数 f ( i ) f(i) f(i)代表数列中第 i 个元素之后第一个大于 a i …

核心篇-OSPF技术之序(下)

文章目录 一. 实验专题1.1. 实验1&#xff1a;配置OSPF特殊区域1.1.1. 实验目的1.1.2. 实验拓扑图1.1.3. 实验步骤&#xff08;1&#xff09;配置IP地址&#xff08;2&#xff09;创建环回口&#xff08;3&#xff09;查看路由表&#xff08;4&#xff09;设置Stub区域&#xf…

linux 安装docker

目录 环境 操作步骤 1 下载脚本 2 执行脚本 3 检查docker版本&#xff0c;证明安装成功 环境 阿里云 ubuntu 22.04 64位 操作步骤 参考linux系统安装docker-腾讯云开发者社区-腾讯云 (tencent.com) 1 下载脚本 curl -fsSL https://get.docker.com -o get-docker.sh …

如何使用六图一表七种武器

六图一表七种武器用于质量管理&#xff1a; 描述当遇到问题时应该用那张图来解决&#xff1a; 一、如果题目说出了质量问题需要找原因&#xff1f; 解&#xff1a;用因果图&#xff0c;因果图也称石川图或鱼骨图 二、如果要判断过程是否稳定受控&#xff1f; 解&#xff1a…

Kotlin基本语法3集合

1.List集合 1.1 只读List fun main() {val list listOf("Jason", "Jack", "Jacky")println(list.getOrElse(3){"Unknown"})println(list.getOrNull(3)?:"Unknown") } 1.2 可变List fun main() {val mutableList mutabl…

幻兽帕鲁服务器如何设置定时清理内存?内存优化(设置Swap、虚拟内存)

幻兽帕鲁服务器可以通过设置定时重启游戏&#xff0c;来达到定时清理内存的目的。也可以通过安装定时清理内存的软件&#xff0c;来设置。还可以通过设置虚拟内存来设置。设置的方法如下&#xff1a; 1、腾讯云一键部署幻兽帕鲁&#xff0c;部署好之后&#xff0c;只需要在控制…

2024 CKS 题库 | 6、创建 Secret

不等更新题库 CKS 题库 6、创建 Secret Task 在 namespace istio-system 中获取名为 db1-test 的现有 secret 的内容 将 username 字段存储在名为 /cks/sec/user.txt 的文件中&#xff0c;并将password 字段存储在名为 /cks/sec/pass.txt 的文件中。 注意&#xff1a;你必须创…

C++集群聊天服务器 muduo+nginx+redis+mysql数据库连接池 笔记 (下)

C集群聊天服务器 网络模块业务模块CMake构建项目 笔记 &#xff08;上&#xff09;-CSDN博客https://blog.csdn.net/weixin_41987016/article/details/135991635?spm1001.2014.3001.5501C集群聊天服务器 数据模块业务模块CMake构建项目 笔记 &#xff08;上&#xff09;-CSDN博…

Java双非无实习秋招进大厂历程

从转后端到拿到Offer,约一年半。 背景介绍 进了快手(如果你觉得不是大厂那就不是!)&#xff1a; 真双非本科: 安徽某双非无实习: 因为编程语言问题,去过之后发现不喜欢,几天跑路!(某小厂,2023.8)竞赛水: 大创(做的安卓软件)起到一个外观上的作用吧...2022.3 大二下转的后端: …

leetcode 160 相交链表

题目 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&#xff0c;函数返回结…