最近我在一次采访中被问到全局寄存器变量。我搞砸了说任何全局变量都将存储在数据段中。但后来我被问及GCC。在采访后我得出结论gcc支持全局寄存器变量。
#include<stdio.h>
register int var asm("ebx"); //storing global variable in register explicitly
int main(void)
{
.......
}
这是链接https://gcc.gnu.org/onlinedocs/gcc/Global-Reg-Vars.html#Global-Reg-Vars
但现在我对它的生命周期和范围感到困惑,是否它将作为普通的全局变量或寄存器变量工作?还有gcc上的任何方法或命令,以便我们确保编译器不会简单地忽略register
关键字并将存储在实际的寄存器中吗?
正如许多人所指出的那样,在全球范围内保留登记册通常是一个坏主意。我相信这里的原意是(来自docs):
这在诸如编程语言解释器之类的程序中可能是有用的,这些程序语言解释器具有经常访问的几个全局变量。
这是否真的有用,或者只是让事情变得更糟可能只能针对特定情况来确定。在您的情况下(面试问题),这并不重要。
像这样的声明的范围就是看到声明的所有内容,正如您对任何全局声明所期望的那样。
但是,实现有点棘手。再次引用文档:
在某个寄存器中定义一个全局寄存器变量,该寄存器完全用于此用途,至少在当前编译中。寄存器不会在当前编译的功能中分配用于任何其他目的,并且不会由这些功能保存和恢复。
因此,使用该声明进行COMPILED的所有代码都将保留该用途的寄存器。但是,如果您链接到未使用此预留编译的其他代码,则不会将其保留用于此目的。
文档给出了qsort的一个很好的例子。如果您的代码是使用此声明编译的,然后它从c运行时调用qsort(可能不会使用此声明编译),然后qsort调用回代码(对于compare函数),回调不能在调用比较函数之前,请确保qsort没有踩踏寄存器。
如果调用任何库函数可以踩踏寄存器,它怎么能工作?再次来自文档:
选择一个通常由机器上的函数调用保存和恢复的寄存器,这样库例程就不会破坏它。
即便如此:
从信号处理程序或多个控制线程访问全局寄存器变量是不安全的,因为系统库例程可能暂时将该寄存器用于其他事情(除非您专门针对手头的任务重新编译它们)。
至于你问题的最后部分:
编译器不会简单地忽略register关键字,而是存储在实际的寄存器中
我不确定你是什么意思。如果(某种程度上)编译器忽略了asm("ebx")
,那么它将不会存储在寄存器中。使用它的全部要点是确保var
存储在实际的ebx寄存器中。