如何在寄存器中存储c++变量
How to store a C++ variable in a register
我想澄清一下关于寄存器变量存储的一点:是否有一种方法来确保,如果我们已经声明了一个寄存器变量在我们的代码,它将只存储在一个寄存器?
#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)。-end note]
事实上,register
存储类说明符在c++ 11中已被弃用(附录D.2):
不赞成使用
register
关键字作为存储类说明符(7.1.1)。
注意,在C语言中不能取register
变量的地址,因为寄存器没有地址。这个限制在c++中被删除了,并且获取地址几乎可以保证变量不会在寄存器中结束。
许多现代编译器直接忽略c++中的register
关键字(当然,除非它以无效的方式使用)。他们只是在优化方面比register
关键字有用的时候要好得多。我希望针对特定目标平台的编译器能更认真地对待它。
关键字register
在C和c++中有不同的含义。在c++中,它实际上是多余的,现在甚至似乎已经被弃用了。
在C中是不同的。首先,不要从字面上理解关键字的名称,它并不总是与现代CPU上的"硬件寄存器"有关。对register
变量施加的限制是不能获取它们的地址,不允许&
操作。这允许您标记变量以进行优化,并确保如果您试图获取其地址,编译器会向您大喊大叫。特别是一个register
变量,同时也是const
合格的,它永远不能别名,所以它是一个很好的优化候选者。
在C语言中使用register
系统地迫使您考虑您取变量地址的每个位置。这可能不是您想在c++中做的事情,因为c++严重依赖于对对象的引用之类的东西。这可能就是为什么c++没有从C中复制register
变量的这个属性的原因。
通常这是不可能的。具体来说,人们可以采取某些措施来增加这种可能性:
使用适当的优化级别。-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
一般来说,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
这只是对编译器的一个提示;您不能强制将变量放入寄存器中。在任何情况下,编译器编写者可能比应用程序程序员更了解目标体系结构,因此更适合编写做出寄存器分配决策的代码。换句话说,您不太可能通过使用register
实现任何目标。
register关键字是编译器必须适应具有2MB RAM的机器(在18个终端之间共享,每个终端都有一个用户登录)的时代遗留下来的。或者128-256KB内存的PC/家用电脑。此时,编译器无法真正遍历一个大函数,以确定哪个寄存器用于哪个变量,从而最有效地使用寄存器。因此,如果程序员用register
给出一个"提示",编译器会把它放在寄存器中(如果可能的话)。
现代编译器在2MB的内存中不能容纳好几次,但是它们在为寄存器分配变量方面要聪明得多。在给出的例子中,我发现编译器不把它放在寄存器中是非常不可能的。显然,寄存器的数量是有限的,并且给定一段足够复杂的代码,有些变量不适合放在寄存器中。但是对于这样一个简单的例子,一个现代的编译器将把i
变成一个寄存器,并且它可能直到ostream& ostream::operator<<(ostream& os, int x)
的某个地方才会接触内存。
确保您正在使用寄存器的唯一方法是使用内联汇编。但是,即使这样做,也不能保证编译器不会将值存储在内联汇编块的之外。当然,你的操作系统可能会决定在任何时候中断你的程序,将所有寄存器存储到内存中,以便将CPU分配给另一个进程。
因此,除非您在内核中编写禁用所有中断的汇编代码,否则绝对没有办法确保变量永远不会击中内存。
当然,这只有在你关心安全的时候才有意义。从性能的角度来看,使用-O3
编译通常是足够的,编译器通常在确定在寄存器中保存哪些变量方面做得很好。无论如何,在寄存器中存储变量只是性能调优的一个小方面,更重要的方面是确保在内部循环中不会完成多余或昂贵的工作。
这里您可以在c++中使用volatile register int i = 10
来确保i
被存储在寄存器中。volatile
关键字将不允许编译器优化变量i
。
- 将字符串存储在c++中的稳定内存中
- std::原子加载和存储都需要吗
- C++:将控制台输出存储在宏中更好吗
- 使用QProcess执行命令,并将结果存储在QStringList中
- 访问存储在向量C++中的结构的多态成员
- 如何从存储在std::映射中的std::集中删除元素
- 存储模板类型以强制转换回派生<T>
- 类型总是使用其大小存储在内存中吗
- 当字符串存储在变量中时,如何将字符串转换为wchar_t
- 使用无符号字符数组有效存储内存
- 如何在cpp.中使用协议缓冲区存储大缓冲区/数组(char/int)
- 使用 pqxx 将 std::vector 存储在 postgresql 中,并从数据库中检索它
- 带结构的二维矢量:如何存储元素
- 添加存储在向量中的大整数的函数出现问题
- 从文件中读取多个字节,并将它们存储在C++中进行比较
- 在std::vector上存储带有模板的类实例
- 谷歌测试中的期望值存储在哪里
- 为什么C中的通用链表中存储的数据已损坏
- 在c++中获取两个大int,并将它们存储在数组中
- 在reactor中存储eventHandlers的最佳方式是什么