C语言中register变量(数据类型:register)的概念是什么?

4
我想了解一下寄存器变量在C程序可执行文件中的处理方式,即在嵌入式系统和X86桌面PC中的确切位置(或寄存器)存储位置是什么?
你认为这种观点怎么样?(如果我错了,请纠正我)
假设我们在一个函数中声明/初始化了一个'int'数据类型的变量。通常它会进入堆栈段,并且只有在调用者调用包含局部变量的被调用者时,在该部分才会存在。但是,如果我们将上述局部变量声明为'register int',那么它也将进入堆栈段。但是运行时,由于'register'关键字造成的额外编译器插入代码,处理器将该局部变量从堆栈放入其通用寄存器位置,并从那里快速访问相同的变量。
它们之间唯一的区别在于运行时访问,它们之间没有内存加载差异。
__Kanu

如果编译器选择将其放入寄存器中,它可能会选择“最佳”寄存器(假定该寄存器从现在起将被用于其他事情的时间最长)。 - TofuBeer
意思是编译器应该精确地知道寄存器地址,并在加载可执行文件时进入该寄存器集,对吗? - Renjith G
从我所知道的所有汇编语言(已经很长时间了),是的,编译器在编译时生成它。从程序员的角度来看,你不应该关心它在哪里。 - TofuBeer
根据我的理解(如果我错了请纠正),编译器只依赖于目标架构,对吗? - Renjith G
这个回答解决了你的问题吗?在C语言中,“register”关键字是什么意思? - Sankalp
5个回答

10

register 关键字在 C 语言中(现在已经很少使用了)只是向编译器提示,可能将变量保存在寄存器中以便更快地访问。

编译器有权忽略此提示,并根据最佳方式进行优化。

由于现代编译器比人类更擅长理解用法和速度,因此现代编译器通常会忽略 register 关键字,在某些情况下,实际上可能会减慢执行速度。


“为了更快地访问,将变量保存在寄存器中可能很有用。” 它占用哪个寄存器内存(通用寄存器/高速缓存/暂存器/RAM/?)? - Renjith G
3
请注意,如果你使用 register 关键字声明一个变量,那么就不能再获取该变量的地址。 - Brian Hooper
@Renjith: "register" 仅指 CPU 寄存器(通常命名为 AX、BX、ES 等),而不是缓存、RAM、L1、L2 或其他你提到的任何东西。我们只谈论最终、最低级别的 CPU 寄存器。 - abelenky
在X86机器上,C程序中允许的寄存器变量声明的最大数量是多少?OK。好的。 - Renjith G
@Renjith:没有限制。寄存器只是编译器的提示,而不是指令。您可以“建议”将数十个或数百个变量存储在寄存器中。编译器将无法满足您所有的请求,只能尽力挑选一些。 - abelenky
其实,你第一次说的是对的:现代编译器会忽略所有的寄存器请求,并自行选择。 - MSalters

7

来自K&R C:

寄存器变量建议编译器使用频繁的变量。这个想法是将寄存器变量放在机器寄存器中,这可能会导致程序更小、更快。但编译器可以忽略这个建议。

无论变量是否实际放置在寄存器中,都不可能获取寄存器变量的地址。

因此,

register int x;
int *y = &x; // is illegal  

因此,您必须权衡无法获取寄存器变量地址的弊端。

4
除了加密的答案(我投票支持)之外,只需看到关键字的名称register就可以将其视为历史上的误称。它与你在课堂上学习von Neumann处理器模型时学到的寄存器没有太多关系,而只是向编译器暗示该变量不需要地址。
在现代计算机上,一个无地址变量可以通过不同的方式实现(例如,立即汇编操作符),或者完全优化掉。将变量标记为register可以是编译器的有用优化提示,也是程序员的有用纪律。

1
+1:更多信息请参见此处:http://gustedt.wordpress.com/2010/08/17/a-common-misconsception-the-register-keyword/ - Matt Joiner

1
当编译器将其内部代码与后端转换为目标处理器的机器/汇编代码时,它会在创建代码时跟踪生成指令的寄存器。当需要分配一个寄存器来加载或跟踪变量时,如果有未使用的工作变量,则将其标记为已使用,并使用该寄存器生成指令。但是,如果所有工作寄存器都有内容,那么通常会将其中一个寄存器的内容驱逐到其他地方,例如全局内存或堆栈(如果该变量有一个位置)。编译器可能对此决策聪明也可能不聪明,并且可能会驱逐高度使用的变量。通过使用寄存器关键字,取决于编译器,您可以影响该决策,它可能选择将寄存器关键字变量保留在寄存器中,并根据需要将非寄存器关键字变量驱逐到内存中。

0
在嵌入式系统和X86机器(桌面PC上可执行的C程序)中,确切存储在哪个位置(或寄存器)是不确定的,需要打开汇编输出进行检查,但由于编译器选择的不同,结果可能会有所偏移。检查汇编代码对于教育目的是一个好主意。
如果您需要精确读写特定的寄存器,应编写内联汇编或链接汇编模块。
通常,在使用标准的C编译器进行x86/amd64编译(如gcc、icc、cl)时,可以合理地假设编译器会为大多数目的进行足够的优化。
然而,如果您使用的是非标准编译器,例如为新嵌入式系统设计的编译器,则最好考虑手动优化。如果架构是新的,则还应考虑手动优化。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接