从站点读取时,您无法创建寄存器类型的全局变量。为什么会这样?来源: http: //publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp ?topic=/com.ibm.xlcpp8l.doc/language/ref/regdef.htm
9 回答
理论上,您可以将处理器寄存器分配给全局范围变量——该寄存器只需在程序的整个生命周期内一直分配给该变量。
然而,C 编译器通常不会在编译阶段看到整个程序 - 编写 C 标准是为了使每个翻译单元(大致对应于每个.c
文件)可以独立于其他编译单元(编译后的对象稍后链接进入程序)。这就是不允许全局范围寄存器变量的原因 - 当编译器正在编译时b.c
,它无法知道有一个全局变量分配给了寄存器 in a.c
(因此函数 inb.c
必须保留该寄存器中的值)。
实际上,GCC 允许这样做。全局范围内的声明,格式为:
register int foo asm ("r12");
为全局“foo”分配寄存器“r12”(在 x86_64 上)。这有很多限制,相应的手册页可能是对所有麻烦的全局寄存器变量的最佳参考:
因为那会毫无意义。全局变量在应用程序运行时一直存在。这么长时间肯定没有免费的处理器寄存器;)
最初,寄存器变量旨在存储在处理器寄存器中,但全局变量必须存储在数据或 BSS 部分中才能从每个函数中访问。今天,编译器不register
严格解释存储类,所以它仍然主要是出于兼容性原因。
该register
关键字的含义与其名称似乎表明的含义不同,如今它与处理环境的寄存器没有太大关系。(尽管它可能曾经为此选择过。)限制使用声明的变量的唯一文本register
是 this
一元 & 运算符的操作数应为函数指示符、[] 或一元 * 运算符的结果,或指定不是位域且未使用寄存器存储类说明符声明的对象的左值
因此,它对自动变量(您在函数中声明的变量)实施了限制,因此获取此类变量的地址是错误的。然后的想法是编译器可以以任何方式表示这个变量,作为一个寄存器或作为一个立即的汇编程序值等。作为一个程序员,你保证你不会获取它的地址。通常这对全局变量没有多大意义(无论如何它们都有地址)。
总结一下:
- 不,
register
关键字不会被忽略。 - 是的,如果您想符合标准,它只能用于堆栈变量
寄存器字在 C/C++ 中用作对编译器的请求,以使用类似变量的处理器寄存器。寄存器是 CPU 使用的一种变量,访问速度非常快,因为它不位于内存 (RAM) 中。寄存器的使用受到架构和寄存器本身大小的限制(这意味着有些可能就像内存指针一样,其他的可以加载特殊的调试值等等)。
C/C++ 使用的调用约定不使用通用寄存器(80x86 Arch 中的 EAX、EBX 等)来保存参数(但返回值存储在 EAX 中),因此您可以声明一个类似寄存器的 var 使代码更快.
如果您要求使其全球化,您要求为所有代码和所有源代码保留寄存器。这是不可能的,所以编译器会给你一个错误,或者干脆把它变成一个存储在内存中的普通变量。
一些编译器提供了一种将寄存器永久专用于变量的方法。然而, register 关键字是不够的。编译器决定在寄存器中为例程分配局部变量通常不需要与其他源模块中的任何东西协调(虽然一些开发系统在例程之间进行寄存器优化,但更常见的是简单地定义调用约定,以便所有例程都允许自由更改某些寄存器(因此如果在函数调用后需要,调用者负责保存内容)但不得更改其他寄存器(因此,如果需要寄存器,被调用例程负责保存和恢复内容)函数)。因此,链接器不需要关心寄存器的使用。
这种方法适用于局部寄存器变量,但对全局变量无用。为了使全局寄存器变量有用,程序员通常必须告诉编译器哪个寄存器用于哪个变量,并确保编译器在编译所有模块时都知道这种保留——即使是那些不使用否则注册。这在嵌入式系统中很有用,特别是对于中断使用的变量,但系统中允许的此类变量的数量通常非常有限(例如 2 个左右)。
那么我们现在都同意了吗?我们是否都看到将全局变量作为寄存器变量是一个非常非常糟糕的主意?如果最初的 C 定义没有禁止它,那可能是因为没有人认为有人会真正以这种方式实现它——因为他们不应该特别回到 CISC 时代。
此外:现代优化编译器在决定何时将变量保存在寄存器中比人类做得更好。如果你做不到,那么你真的,真的需要一个更好的编译器。
因为它们在寄存器中。用词是矛盾的。