16

我想澄清一下关于寄存器变量存储的一点:有没有办法确保如果我们在代码中声明了一个寄存器变量,它只会存储在寄存器中?

#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;
}
4

8 回答 8

30

你不能。这只是对编译器的提示,表明该变量被大量使用。这是 C99 的措辞:

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

这是 C++11 的措辞:

说明register符是对实现的提示,即如此声明的变量将被大量使用。[ 注意:提示可以被忽略,并且在大多数实现中,如果变量的地址被获取,它将被忽略。这种用法已被弃用(见 D.2)。——尾注]

事实上,register存储类说明符在 C++11(附件 D.2)中已被弃用:

不推荐使用register关键字作为存储类说明符(7.1.1)。

请注意,您不能register在 C 中获取变量的地址,因为寄存器没有地址。这个限制在 C++ 中被删除,并且几乎可以保证获取地址以确保变量不会最终出现在寄存器中。

许多现代编译器只是忽略registerC++ 中的关键字(当然,除非它以无效的方式使用)。register与关键字有用时相比,它们在优化方面要好得多。我希望小众目标平台的编译器更认真地对待它。

于 2013-04-09T17:45:14.387 回答
6

register关键字在 C 和 C++ 中具有不同的含义。在 C++ 中,它实际上是多余的,而且现在似乎已被弃用。

在 C 中它是不同的。首先不要从字面上理解关键字的名称,它并不总是与现代 CPU 上的“硬件寄存器”有关。对变量施加的限制是register不能取地址,&不允许操作。这允许您标记一个变量以进行优化,并确保如果您尝试获取它的地址,编译器会向您喊叫。特别是一个register同样合格的变量const永远不能别名,所以它是一个很好的优化候选者。

在 C 中使用registeras 系统地迫使您考虑获取变量地址的每个地方。这可能不是您在 C++ 中想要做的事情,C++ 严重依赖于对对象和类似事物的引用。这可能是 C++ 没有register从 C 复制此变量属性的原因。

于 2013-04-09T21:22:22.240 回答
4

一般是不可能的。具体来说,可以采取一定的措施来增加概率:

使用适当的优化级别,例如。-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
于 2013-04-09T18:01:11.497 回答
3

这只是对编译器的提示;你不能强迫它把变量放在寄存器中。无论如何,编译器编写者可能比应用程序程序员更了解目标体系结构,因此更适合编写做出寄存器分配决策的代码。换句话说,您不太可能通过使用register.

于 2013-04-09T17:45:21.930 回答
2

“register”关键字是编译器必须适应具有 2MB RAM 的机器(在 18 个终端之间共享,每个终端都有一个用户登录)的时代的残余。或具有 128-256KB RAM 的 PC/家用电脑。那时,编译器无法真正运行一个大函数来确定哪个寄存器用于哪个变量,以最有效地使用寄存器。因此,如果程序员使用 给出“提示” register,编译器会将其放入寄存器中(如果可能的话)。

现代编译器无法在 2MB 的 RAM 中多次安装,但它们在将变量分配给寄存器方面要聪明得多。在给出的示例中,我发现编译器不会将其放入寄存器是非常不可能的。显然,寄存器的数量是有限的,并且给定一段足够复杂的代码,一些变量将不适合寄存器。但是对于这样一个简单的例子,现代编译器会创建i一个寄存器,它可能直到内部的某个地方才会触及内存ostream& ostream::operator<<(ostream& os, int x)

于 2013-04-09T18:20:26.247 回答
2

确保您使用寄存器的唯一方法是使用内联汇编。但是,即使您这样做,也不能保证编译器不会将您的值存储在内联汇编块之外。当然,您的操作系统可能会决定在任何时候中断您的程序,将所有寄存器存储到内存中,以便将 CPU 交给另一个进程。

因此,除非您在禁用所有中断的情况下在内核中编写汇编代码,否则绝对无法确保您的变量永远不会撞到内存。

当然,这仅在您担心安全时才有意义。从性能的角度来看,编译-O3通常就足够了,编译器通常可以很好地确定哪些变量要保存在寄存器中。无论如何,将变量存储在寄存器中只是性能调整的一小部分,更重要的方面是确保在内循环中不会完成多余或昂贵的工作。

于 2014-02-12T21:40:18.293 回答
2

通常 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
于 2014-08-04T08:32:11.457 回答
0

在这里您可以volatile register int i = 10在 C++ 中使用以确保i存储在寄存器中。volatile关键字将不允许编译器优化变量i

于 2014-04-06T16:22:38.993 回答