本节书摘来自华章计算机《编写高质量代码:改善c程序代码的125个建议》一书中的第1章,建议8-4,作者:马 伟 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
建议8-4:尽量少使用register变量
前面内容就已经阐述过,计算机中保存变量当前值的存储单元有两类:一类是内存,另一类是CPU的寄存器,而register变量则将其值存储到CPU的寄存器中。通常,寄存器变量比存储于内存的变量访问效率更高。但是,编译器并不一定会理睬register关键字,如果有太多的变量被声明为register,它只会选取前几个实际存储于寄存器中,其余的就按普通变量进行处理。如果一个编译器自己具有一套寄存器优化方法,它也可能会忽略register关键字,其依据是由编译器决定哪些变量存储于寄存器中要比人脑决定更为合理一些。
在典型情况下,通常会希望把使用频率更高的那些变量声明为寄存器变量。在有些计算机中,如果把指针变量声明为寄存器变量,程序的效率将能得到提高,尤其是那些频繁执行间接访问操作的指针。你也可以把函数的形式参数声明为寄存器变量,这样编译器会在函数的起始位置生成指令,然后把这些值从内存复制到寄存器中。但是,完全有可能这个优化措施所节省的时间和空间的开销还抵不上复制这几个值所花的开销。
register变量的使用示例如代码清单1-29所示。
代码清单1-29 register变量的使用示例
#include <stdio.h>
size_t fac(size_t n);
int main(void)
{
size_t i;
for(i=1;i<=5;i++)
{
printf("%d! = %d\n",i,fac(i));
}
return 0;
}
size_t fac(size_t n)
{
register size_t result=1;
register size_t i=1;
for(i=1;i<=n;i++)
{
result=result*i;
}
return result;
}
在代码清单1-29中,我们在fac函数中实现了阶乘功能。因为fac函数中的变量result与i需要在for循环中反复调用,所以这里把它们定义成寄存器变量。其运行结果如图1-43所示。
寄存器变量的创建和销毁时间与自动变量相同,但它需要做一些额外的工作。在一个使用寄存器变量的函数返回之前,这些寄存器必须恢复先前所存储的值,确保调用者的寄存器变量未被破坏。许多机器使用运行时堆栈来完成这个任务。当函数开始执行时,它把需要使用的所有寄存器的内容都保存到内存中,当函数返回时,这些值会再复制到寄存器中。
https://yqfile.alicdn.com/d2cfb3dbaeafc070f34a130cc4a039c4e5dd873c.png" >
值得注意的是,在许多机器的硬件实现中,并不会为寄存器指定地址。同样,某个特定的寄存器在不同的时刻所保存的值也不一定相同。基于这些原因,机器并不会向你提供寄存器变量的地址。因此,在C语言中,你不能够通过“&”操作符来访问register变量的地址。
最后,在使用register变量时,还需要注意如下几个方面:
- 只有局部自动变量和形式参数可以作为寄存器变量,否则将会导致无法编译。
- 一个计算机系统中的寄存器数目有限,不能定义任意多个寄存器变量。
- 局部静态变量不能定义为寄存器变量。
- register变量一般只对整型和字符型数据有用。
- 不能使用取地址运算符“&”求寄存器变量的地址。