当前位置:  开发笔记 > 编程语言 > 正文

C中的"注册"关键字?

如何解决《C中的"注册"关键字?》经验,为你挑选了8个好方法。

什么是register关键字在C语言吗?我已经读过它用于优化,但在任何标准中都没有明确定义.它是否仍然相关,如果是,你什么时候使用它?



1> Brian Knobla..:

这是编译器的一个提示,即变量将被大量使用,如果可能,建议将其保存在处理器寄存器中.

大多数现代编译器会自动执行此操作,并且比我们人类更擅长选择它们.


一个很好的理由_not_使用'register':你不能把变量的地址称为'register'
@Euro:您可能知道这一点,但只是为了明确,编译器需要防止"register"变量的地址被采用; 这是`register`关键字的唯一*强制效果.即使这足以改进优化,因为告诉变量只能在此函数中进行修改变得微不足道.
请注意,一些/多个编译器将完全忽略register关键字(这是完全合法的).
好吧,我尝试使用注册来调整我的ACM提交,有时它确实有帮助.但是你真的必须要很好,因为糟糕的选择会降低性能.
ypnos:实际上,ACM ICPC问题解决方案的速度更多地取决于算法选择而不是微观优化.5秒的时间限制通常足以提供正确的解决方案,尤其是在使用C而不是Java时.
它在嵌入式中仍然非常有用.嵌入式系统的体面编译器甚至允许您设置哪个变量进入哪个寄存器.

2> qrdl..:

令我感到惊讶的是,没有人提到你不能获取寄存器变量的地址,即使编译器决定将变量保存在内存而不是寄存器中.

因此,使用register你什么都不赢(无论如何编译器将自己决定放置变量的位置)并失去&操作员 - 没有理由使用它.


实际上有一个原因.事实上,你不能获取变量的地址会产生一些优化机会:编译器可以证明变量不会有别名.
通过这个逻辑,`const`也没用,因为它不会赢你,你只能失去改变变量的能力.`register`可以用来确保将来没有人不考虑变量的地址.我从来没有理由使用`register`.
众所周知,编译器在证明在非平凡的情况下不会出现混叠是非常糟糕的,因此即使编译器没有将寄存器放入寄存器,`register`对此也很有用.
@ AlexandreC,Miles,编译器可以很好地检查&是否在任何地方使用了变量。因此,无论在检测锯齿方面有其他困难,重述都无济于事。当K + R首次创建C时,事先*知道将不使用&确实很有用,因为该编译器实际上是在查看以下代码之前,先根据声明来决定寄存器分配的。这就是为什么禁止的地方。'register'关键字现在实际上已经过时了。

3> Andrew Barne..:

它告诉编译器尝试使用CPU寄存器而不是RAM来存储变量.寄存器位于CPU中,访问速度比RAM快得多.但这只是对编译器的一个建议,它可能无法完成.


值得为使用C++的人添加,C++允许您获取寄存器变量的地址
@Will:...但编译器最终可能会忽略关键字.看我的回答.

4> bwDraco..:

我知道这个问题是关于C的,但是关于C++的同一个问题被完全复制了.因此,这个答案可能不适用于C.


最新的C++ 11标准草案N3485在7.1.1/3中说明了这一点:

一个register说明符是一种提示,如此声明的变量将被频繁使用的实现.[ 注意:提示可以忽略,在大多数实现中,如果采用变量的地址,它将被忽略.这个用法已被弃用... -end note ]

在C++中(但不是在C中),标准并未声明您不能获取声明的变量的地址register; 但是,因为存储在CPU寄存器中的变量在其整个生命周期中没有与之关联的存储单元,所以尝试获取其地址将无效,并且编译器将忽略该register关键字以允许获取该地址.



5> Paul Tomblin..:

由于优化者对此做出了比这更好的决策,因此至少15年没有相关性.即使它是相关的,它在具有许多寄存器的CPU架构上更有意义,例如SPARC或M68000,而不是因为缺少寄存器的英特尔,其中大多数寄存器由编译器保留用于其自身目的.



6> Keith Thomps..:

我已经读过它用于优化,但在任何标准中都没有明确定义.

事实上,它由C标准明确定义的.引用N1570草案第6.7.1节第6段(其他版本具有相同的措辞):

具有存储类说明符的对象的标识符声明register表明对对象的访问尽可能快.这些建议有效的程度是实施定义的.

一元运算&符可能不适用于定义的对象register,register也不能用于外部声明.

还有一些其他(相当模糊的)规则是特定于register限定对象的:

定义register具有未定义行为的数组对象.
更正:定义数组对象是合法的register,但是你不能对这样的对象做任何有用的事情(索引到数组需要获取其初始元素的地址).

_Alignas说明符(在C11新)可以不被应用到这样一个对象.

如果传递给va_start宏的参数名称是register-qualified,则行为是未定义的.

可能还有其他几个; 如果您有兴趣,请下载标准草案并搜索"注册".

顾名思义,该原始的含义register是要求的对象将被存储在一个CPU寄存器.但随着优化编译器的改进,这已变得不那么有用了.C标准的现代版本不涉及CPU寄存器,因为它们不再(需要)假设存在这样的事情(存在不使用寄存器的架构).常识是,应用于register对象声明更有可能使生成的代码恶化,因为它会干扰编译器自己的寄存器分配.可能仍然存在一些有用的情况(例如,如果您确实知道变量的访问频率,并且您的知识优于现代优化编译器可以解决的问题).

主要的实际效果register是它可以防止任何尝试获取对象的地址.这不是特别有用的优化提示,因为它只能应用于局部变量,并且优化编译器可以看到自己没有采用这样的对象的地址.



7> 小智..:

实际上,register告诉编译器该变量不与程序中的任何其他内容(甚至不是char)进行别名.

现代编译器可以在各种情况下利用它,并且可以在复杂的代码中帮助编译器 - 在简单的代码中,编译器可以自己解决这个问题.

否则,它没有用处,也不用于寄存器分配.只要编译器足够现代,它通常不会导致性能下降.



8> Orion..:

讲故事的时间!

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:执行大量数学运算的短期变量.不要一次声明太多.

推荐阅读
雨天是最美
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有