我想澄清一下关于寄存器变量存储的一点:有没有办法确保如果我们在代码中声明了一个寄存器变量,它只会存储在寄存器中?
#include<iostream>
using namespace std;
int main()
{
register int i = 10;// how can we ensure this will store in register only.
i++;
cout << i << endl;
return 0;
}
我想澄清一下关于寄存器变量存储的一点:有没有办法确保如果我们在代码中声明了一个寄存器变量,它只会存储在寄存器中?
#include<iostream>
using namespace std;
int main()
{
register int i = 10;// how can we ensure this will store in register only.
i++;
cout << i << endl;
return 0;
}
你不能。这只是对编译器的提示,表明该变量被大量使用。这是 C99 的措辞:
为具有存储类说明符的对象声明标识符
register
表明对对象的访问尽可能快。这些建议的有效程度由实施定义。
这是 C++11 的措辞:
说明
register
符是对实现的提示,即如此声明的变量将被大量使用。[ 注意:提示可以被忽略,并且在大多数实现中,如果变量的地址被获取,它将被忽略。这种用法已被弃用(见 D.2)。——尾注]
事实上,register
存储类说明符在 C++11(附件 D.2)中已被弃用:
不推荐使用
register
关键字作为存储类说明符(7.1.1)。
请注意,您不能register
在 C 中获取变量的地址,因为寄存器没有地址。这个限制在 C++ 中被删除,并且几乎可以保证获取地址以确保变量不会最终出现在寄存器中。
许多现代编译器只是忽略register
C++ 中的关键字(当然,除非它以无效的方式使用)。register
与关键字有用时相比,它们在优化方面要好得多。我希望小众目标平台的编译器更认真地对待它。
该register
关键字在 C 和 C++ 中具有不同的含义。在 C++ 中,它实际上是多余的,而且现在似乎已被弃用。
在 C 中它是不同的。首先不要从字面上理解关键字的名称,它并不总是与现代 CPU 上的“硬件寄存器”有关。对变量施加的限制是register
不能取地址,&
不允许操作。这允许您标记一个变量以进行优化,并确保如果您尝试获取它的地址,编译器会向您喊叫。特别是一个register
同样合格的变量const
永远不能别名,所以它是一个很好的优化候选者。
在 C 中使用register
as 系统地迫使您考虑获取变量地址的每个地方。这可能不是您在 C++ 中想要做的事情,C++ 严重依赖于对对象和类似事物的引用。这可能是 C++ 没有register
从 C 复制此变量属性的原因。
一般是不可能的。具体来说,可以采取一定的措施来增加概率:
使用适当的优化级别,例如。-O2
保持变量的数量很小
register int a,b,c,d,e,f,g,h,i, ... z; // can also produce an error
// results in _spilling_ a register to stack
// as the CPU runs out of physical registers
不要获取寄存器变量的地址。
register int a;
int *b = &a; /* this would be an error in most compilers, but
especially in the embedded world the compilers
release the restrictions */
在某些编译器中,您可以建议
register int a asm ("eax"); // to put a variable to a specific register
这只是对编译器的提示;你不能强迫它把变量放在寄存器中。无论如何,编译器编写者可能比应用程序程序员更了解目标体系结构,因此更适合编写做出寄存器分配决策的代码。换句话说,您不太可能通过使用register
.
“register”关键字是编译器必须适应具有 2MB RAM 的机器(在 18 个终端之间共享,每个终端都有一个用户登录)的时代的残余。或具有 128-256KB RAM 的 PC/家用电脑。那时,编译器无法真正运行一个大函数来确定哪个寄存器用于哪个变量,以最有效地使用寄存器。因此,如果程序员使用 给出“提示” register
,编译器会将其放入寄存器中(如果可能的话)。
现代编译器无法在 2MB 的 RAM 中多次安装,但它们在将变量分配给寄存器方面要聪明得多。在给出的示例中,我发现编译器不会将其放入寄存器是非常不可能的。显然,寄存器的数量是有限的,并且给定一段足够复杂的代码,一些变量将不适合寄存器。但是对于这样一个简单的例子,现代编译器会创建i
一个寄存器,它可能直到内部的某个地方才会触及内存ostream& ostream::operator<<(ostream& os, int x)
。
确保您使用寄存器的唯一方法是使用内联汇编。但是,即使您这样做,也不能保证编译器不会将您的值存储在内联汇编块之外。当然,您的操作系统可能会决定在任何时候中断您的程序,将所有寄存器存储到内存中,以便将 CPU 交给另一个进程。
因此,除非您在禁用所有中断的情况下在内核中编写汇编代码,否则绝对无法确保您的变量永远不会撞到内存。
当然,这仅在您担心安全时才有意义。从性能的角度来看,编译-O3
通常就足够了,编译器通常可以很好地确定哪些变量要保存在寄存器中。无论如何,将变量存储在寄存器中只是性能调整的一小部分,更重要的方面是确保在内循环中不会完成多余或昂贵的工作。
通常 CPP 编译器 (g++) 会对代码进行很多优化。因此,当您声明一个寄存器变量时,编译器没有必要将该值直接存储在寄存器中。(即)代码“register int x”可能不会导致编译器将该 int 直接存储在寄存器中。但是如果我们可以强制编译器这样做,我们可能会成功。
例如,如果我们使用下面的一段代码,那么我们可能会强制编译器做我们想做的事情。以下代码的编译可能会出错,这表明 int 实际上是直接存储在寄存器中的。
int main() {
volatile register int x asm ("eax");
int y = *(&x);
return 0;
}
对我来说,g++ 编译器在这种情况下会抛出以下错误。
[nsidde@nsidde-lnx cpp]$ g++ register_vars.cpp
register_vars.cpp: In function ‘int main()’:
register_vars.cpp:3: error: address of explicit register variable ‘x’ requested
'volatile register int x asm ("eax")' 行指示编译器将整数 x 存储在 'eax' 寄存器中,并且这样做不做任何优化。这将确保该值直接存储在寄存器中。这就是为什么访问变量的地址会引发错误。
或者,C 编译器 (gcc) 可能会因以下代码本身出错。
int main() {
register int a=10;
int c = *(&a);
return 0;
}
对我来说,gcc 编译器在这种情况下会抛出以下错误。
[nsidde@nsidde-lnx cpp]$ gcc register.c
register.c: In function ‘main’:
register.c:5: error: address of register variable ‘a’ requested
在这里您可以volatile register int i = 10
在 C++ 中使用以确保i
存储在寄存器中。volatile
关键字将不允许编译器优化变量i
。