什么是register
关键字在C语言吗?我已经读过它用于优化,但在任何标准中都没有明确定义.它是否仍然相关,如果是,你什么时候使用它?
这是编译器的一个提示,即变量将被大量使用,如果可能,建议将其保存在处理器寄存器中.
大多数现代编译器会自动执行此操作,并且比我们人类更擅长选择它们.
令我感到惊讶的是,没有人提到你不能获取寄存器变量的地址,即使编译器决定将变量保存在内存而不是寄存器中.
因此,使用register
你什么都不赢(无论如何编译器将自己决定放置变量的位置)并失去&
操作员 - 没有理由使用它.
它告诉编译器尝试使用CPU寄存器而不是RAM来存储变量.寄存器位于CPU中,访问速度比RAM快得多.但这只是对编译器的一个建议,它可能无法完成.
我知道这个问题是关于C的,但是关于C++的同一个问题被完全复制了.因此,这个答案可能不适用于C.
最新的C++ 11标准草案N3485在7.1.1/3中说明了这一点:
一个
register
说明符是一种提示,如此声明的变量将被频繁使用的实现.[ 注意:提示可以忽略,在大多数实现中,如果采用变量的地址,它将被忽略.这个用法已被弃用... -end note ]
在C++中(但不是在C中),标准并未声明您不能获取声明的变量的地址register
; 但是,因为存储在CPU寄存器中的变量在其整个生命周期中没有与之关联的存储单元,所以尝试获取其地址将无效,并且编译器将忽略该register
关键字以允许获取该地址.
由于优化者对此做出了比这更好的决策,因此至少15年没有相关性.即使它是相关的,它在具有许多寄存器的CPU架构上更有意义,例如SPARC或M68000,而不是因为缺少寄存器的英特尔,其中大多数寄存器由编译器保留用于其自身目的.
我已经读过它用于优化,但在任何标准中都没有明确定义.
事实上,它是由C标准明确定义的.引用N1570草案第6.7.1节第6段(其他版本具有相同的措辞):
具有存储类说明符的对象的标识符声明
register
表明对对象的访问尽可能快.这些建议有效的程度是实施定义的.
一元运算&
符可能不适用于定义的对象register
,register
也不能用于外部声明.
还有一些其他(相当模糊的)规则是特定于register
限定对象的:
定义register
具有未定义行为的数组对象.
更正:定义数组对象是合法的register
,但是你不能对这样的对象做任何有用的事情(索引到数组需要获取其初始元素的地址).
的_Alignas
说明符(在C11新)可以不被应用到这样一个对象.
如果传递给va_start
宏的参数名称是register
-qualified,则行为是未定义的.
可能还有其他几个; 如果您有兴趣,请下载标准草案并搜索"注册".
顾名思义,该原始的含义register
是要求的对象将被存储在一个CPU寄存器.但随着优化编译器的改进,这已变得不那么有用了.C标准的现代版本不涉及CPU寄存器,因为它们不再(需要)假设存在这样的事情(存在不使用寄存器的架构).常识是,应用于register
对象声明更有可能使生成的代码恶化,因为它会干扰编译器自己的寄存器分配.可能仍然存在一些有用的情况(例如,如果您确实知道变量的访问频率,并且您的知识优于现代优化编译器可以解决的问题).
主要的实际效果register
是它可以防止任何尝试获取对象的地址.这不是特别有用的优化提示,因为它只能应用于局部变量,并且优化编译器可以看到自己没有采用这样的对象的地址.
实际上,register告诉编译器该变量不与程序中的任何其他内容(甚至不是char)进行别名.
现代编译器可以在各种情况下利用它,并且可以在复杂的代码中帮助编译器 - 在简单的代码中,编译器可以自己解决这个问题.
否则,它没有用处,也不用于寄存器分配.只要编译器足够现代,它通常不会导致性能下降.
讲故事的时间!
C,作为一种语言,是计算机的抽象.它允许您根据计算机的功能执行操作,即操作内存,执行数学操作,打印内容等.
但C只是一种抽象.最终,它从你身上汲取的是汇编语言.汇编是CPU读取的语言,如果使用它,则根据CPU执行操作.CPU做什么?基本上,它从内存中读取数据,并写入内存.CPU不只是对内存中的数字进行数学运算.首先,您必须将一个数字从内存移动到CPU内部称为寄存器的内存中.一旦完成了对此数字所做的任何操作,就可以将其移回正常的系统内存.为什么要使用系统内存?登记册的数量有限.在现代处理器中你只能获得大约一百个字节,而较旧的流行处理器则更受限制(6502有3个8位寄存器供你免费使用).所以,你的平均数学运算如下:
load first number from memory load second number from memory add the two store answer into memory
很多是......不是数学.这些加载和存储操作可能需要一半的处理时间.C,作为计算机的抽象,使程序员免于使用和处理寄存器的担忧,并且由于计算机之间的数量和类型不同,C将寄存器分配的责任完全放在编译器上.有一个例外.
当你声明一个变量时register
,你告诉编译器"哟,我打算让这个变量被大量使用和/或短暂存在.如果我是你,我会尝试将它保存在寄存器中." 当C标准说编译器不必实际做任何事情时,那是因为C标准不知道你正在编译什么计算机,它可能就像上面的6502那样,只需操作所有3个寄存器,并没有备用寄存器来保存您的电话号码.但是,当它说你无法获取地址时,那是因为寄存器没有地址.他们是处理器的手.由于编译器不必为您提供地址,并且由于它根本不能有地址,因此现在可以对编译器进行多次优化.例如,它可以始终将数字保存在寄存器中.它不必担心它存储在计算机内存中的位置(除了需要再次将其恢复).它甚至可以将它变成另一个变量,将它交给另一个处理器,给它一个不断变化的位置等等.
tl; dr:执行大量数学运算的短期变量.不要一次声明太多.