当前位置: 首页 > news >正文

C语言register关键字与volatile关键字

CPU的基本组成

要讲这个,我们先要介绍一下CPU的组成
CPU由运算器与控制器组成,而现代CPU内部通常也集成了存储器
这里这个存储器又包含:

  • 寄存器
  • L1 Cache(一级缓存)
  • L2 Cache(二级缓存)
  • L3 Cache(三级缓存)
    其中下面三个可以统称为CPU缓存。
    寄存器就是被CPU直接操控的数据存储区
    而缓存是CPU和内存之间的缓冲区
    而在CPU外部,还有一个存储设备RAM,就是我们常说的内存
存储单元容量速度位置
寄存器几十~几百字节最快CPU核心内部
L1 Cahce几十KB极快CPU核心内部
L2 Cache几百KB~数MB很快CPU核心内部
L3 Cache几MB~数十MB较快多核心共享
RAMGB级较慢CPU外部

缓存的作用可以这样说,假如一个程序要利用一个数组[1,2,3,4,5]的所有数据,但是如果每次读一个数据都要通过总线从内存拿,这样效率会有一点低下。我们在运行这个程序的时候可以直接把[1,2,3,4,5]这整个数组先拿到缓存里,这样后续访问就会快很多。
本质区别可以用这两句话概括:
寄存器:

CPU正在计算的数据

缓存:

CPU未来可能要计算的数据

register关键字

我们直接看最本质、最核心的区别:

#include<stdio.h> int main() { int m = 1; while(1) { printf("%d",m); } return 0; }

这段代码写了一个死循环,一直输出变量m的值
但是,这有一个问题会影响效率。在我们程序运行时,程序会从硬盘中被拉取到内存中。每一次循环,都要执行一次打印m的值的语句,而这个语句每次执行都要CPU通过总线从内存中读取变量m的值,这就会影响效率。但是解决很简单,这样写就可以解决这个问题:

#include<stdio.h> int main() { register int m = 1; while(1) { printf("%d",m); } return 0; }

对比可以发现,和上一个代码的区别仅仅是这个代码在定义变量m的时候多了一个register关键字。
register关键字的作用就是,建议编译器把我们定义的变量放入CPU寄存器。
看我们的代码,如果变量m被放入了寄存器,那么在while每一次循环都不需要再与内存交互而是直接从寄存器中读取变量m的值,大大提高了程序运行效率。
几个注意点:

  • 加了register关键字并不代表编译器一定会把这个变量存在寄存器,只是建议编译器把这个变量存在寄存器,具体要看寄存器的空间情况。
  • register关键字只能修饰局部变量的定义,不能修饰全局变量的定义和函数定义。
  • 不能使用取地址运算符&对被register关键字标记的变量进行取地址运算。因为取地址运算符只能对在内存中的变量获得其内存地址,而寄存器中的变量压根不在内存中。
  • register修饰的变量一定要是CPU所能处理的类型(比如有的CPU不支持浮点,用register标记浮点就会出问题
  • register适用于标记某一个被频繁使用的变量
    不过,在早期的C语言编译器中,register非常有用。但是,现代编译器(如 GCC, Clang)的优化算法(比如开启-O2-O3优化)已经非常强大了。编译器自己就能完美判断出哪些变量被频繁使用,并自动将它们放入寄存器中。但是我们依然要重视这个关键字的使用。

volatile关键字

volatile在英文中的意思是异变的、动荡不定的
volatile关键字的作用是标记被这个关键字修饰的变量随时可能发生变化
可以看这个例子

#include<stdio.h> int main() { int flag = 0; while(flag==0) { } return 0; }

这里编译器会发现while循环内部压根就没有修改flag的,但是每次循环结束后都要判断一次flag==0,这时候就会进行编译器优化,把flag这个变量拿到寄存器内部,不再利用内存中的flag变量。这就会出现一个问题,如果内存中的flag变量真的被修改了,那么flag不是0了,按理来说循环应该结束,但是还是会执行。
这时候就可以对flagvolatile关键字进行修饰,这样就会阻止编译器优化。绝大部分情况下用于全局变量。
代码如下:

#include<stdio.h> int main() { volatile int flag = 0; while(flag==0) { } return 0; }

总结

这两个关键字都与CPU的寄存器与内存的管理有关,两者有类似之处,一个是建议把变量定义在寄存器中,一个是建议不把变量拉到寄存器中。

http://www.gsyq.cn/news/1544896.html

相关文章:

  • Flow Matching for Generative Models-从generalized的角度来理解diffusion模型
  • Seraphine:3分钟掌握英雄联盟实时战绩查询与智能BP技巧
  • OptiScaler完整指南:5个步骤解锁游戏画质与帧率双重提升
  • Adobe Illustrator脚本集合:设计师必备的70+效率倍增器
  • NetEase-Cloud-Music-DiscordRPC:如何让你的Discord好友随时知道你在听什么音乐?
  • 2026年上海劳动合同纠纷顾问哪家好?5家专业推荐 - 本地品牌推荐
  • 上海崇明区黄金回收商家梯队排行:高价透明款都在这,性价比一目了然 - 沪上贵金属口碑推荐官
  • 终极指南:如何用noScribe将学术访谈转录效率提升300%
  • 电动车托运哪家好?带电池怎么发最划算 - 快递物流资讯
  • 紧急采购指南:HC-276高温耐腐蚀合金快速找厂通道 - 品牌2026
  • GmSSL实战:从安装到SM2证书链生成与全面检测指南
  • 2026年辛安街道专业的空调拆卸服务商有哪些 - 品牌排行榜
  • 上海奉贤区黄金回收深度调研:3家合规机构对比 这样变现最划算 - 沪上贵金属口碑推荐官
  • 构建高效量化交易策略:101个Alpha因子的完整实战指南
  • 2026年中高碑店地区高碑店隆迈风机配件实力厂商深度推荐与解析 - 品牌鉴赏官2026
  • 2026年市北区专业的蹲便疏通公司有哪些 - 品牌排行榜
  • 中兴交换机自动化配置脚本实战指南
  • 高性能内容加载方案:优化用户体验的3种实现方式
  • 2026行业内靠谱的专利律所推荐及选择参考 - 品牌排行榜
  • 2026年东莞专利申请与无效律师哪家好?5位双证专家值得推荐 - 本地品牌推荐
  • 2026上海小程序开发公司排名:十大定制开发服务商盘点 - IT老炮老刘
  • AI协作方法论:从任务拆解到模型匹配的实战指南
  • 战略拆解和战略解码是一个意思吗?
  • 为什么Eloquent模型能映射数据库表?
  • 用Python写一个蜘蛛纸牌求解器:状态建模、DFS回溯与启发式剪枝的完整实现
  • 大师篇-零基础入门PCB设计--PCB布线(信号部分)
  • 乙方项目汇报PPT怎么做才能让甲方眼前一亮?
  • 工厂大脑赋能智能制造设备智能运维升级研究
  • 打破限制:用OpenCore Legacy Patcher让老旧Mac重获新生的完整指南
  • 大数据行业就业学数据分析的价值