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关键字我们直接看最本质、最核心的区别#includestdio.h int main() { int m 1; while(1) { printf(%d,m); } return 0; }这段代码写了一个死循环一直输出变量m的值但是这有一个问题会影响效率。在我们程序运行时程序会从硬盘中被拉取到内存中。每一次循环都要执行一次打印m的值的语句而这个语句每次执行都要CPU通过总线从内存中读取变量m的值这就会影响效率。但是解决很简单这样写就可以解决这个问题#includestdio.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关键字的作用是标记被这个关键字修饰的变量随时可能发生变化可以看这个例子#includestdio.h int main() { int flag 0; while(flag0) { } return 0; }这里编译器会发现while循环内部压根就没有修改flag的但是每次循环结束后都要判断一次flag0这时候就会进行编译器优化把flag这个变量拿到寄存器内部不再利用内存中的flag变量。这就会出现一个问题如果内存中的flag变量真的被修改了那么flag不是0了按理来说循环应该结束但是还是会执行。这时候就可以对flag用volatile关键字进行修饰这样就会阻止编译器优化。绝大部分情况下用于全局变量。代码如下#includestdio.h int main() { volatile int flag 0; while(flag0) { } return 0; }总结这两个关键字都与CPU的寄存器与内存的管理有关两者有类似之处一个是建议把变量定义在寄存器中一个是建议不把变量拉到寄存器中。