为什么创建注册关键字
Why was the register keyword created?
在阅读赫伯·萨特(Herb Sutter)的《不是的关键字》(或另一个名字的评论)时,我遇到了这些行:
没错,一些关键字在语义上等同于空格,一个美化的评论。
和
我们已经了解了为什么C++语言将关键字视为保留字,并且我们已经看到了两个关键字 - auto和register--对C++程序没有任何语义差异。不要使用它们;无论如何,它们只是空格,并且有更快的方法来键入空格。
如果像auto
(也许不在C++11中)和register
这样的关键字没有价值,那么为什么要创建和使用它们?
如果在变量之前包含register
没有任何区别
#include<stdio.h>
int main(){
register int a = 15;
printf("%dn%dn",&a,a);
return 0;
}
为什么上面的程序会给出错误?
test_register.c:在函数"main"中:
test_register.c:4:2:错误:请求寄存器变量"a"的地址
printf("%d%d",&a,a);
以下程序适用于C++。
#include<iostream>
int main(){
register int a = 15;
std::cout<<&a<<'n'<<a;
return 0;
}
寄存器
在 C 语言中,register
存储类用作编译器的提示,以表示变量应优先存储在寄存器中。请注意,在实际寄存器中存储register
变量的提示可能会也可能不会被接受,但在这两种情况下,相关限制仍然适用。见C11,6.7.1p6(强调我的):
使用存储类说明符
register
声明对象的标识符建议尽可能快地访问该对象。这些建议在多大程度上有效,由执行决定。[脚注121][脚注121] 实现可以简单地将任何
register
声明视为auto
声明。但是,无论是否实际使用可寻址存储,都无法显式计算使用存储类说明符register
声明的对象的任何部分的地址(通过使用 6.5.3.2 中讨论的一元和运算符)或隐式(通过将数组名称转换为指针,如 6.3.2.1 中所述)。因此,唯一可以应用于使用存储类说明符register
声明的数组的运算符是sizeof
和_Alignof
。
在C++中,它只是一个未使用的保留关键字,但可以合理地假设它是为了与 C 代码的语法兼容性而保留的。
自动
在 C 中,auto
存储类定义了一个自动存储变量,但通常不使用它,因为默认情况下auto
函数局部变量。
同样,可以合理地假设它最初只是为了语法兼容性而转移到C++,尽管后来它有了自己的含义(类型推断)。
C 语言中的register
有两个目的:
- 向编译器提示变量应存储在寄存器中以提高性能。 这种用法现在基本上已经过时了。
- 防止程序员以阻止变量存储在寄存器中的方式使用该变量。 这种用法只是IMO有些过时。
这类似于const
,它
- 向编译器提示变量可能存储在只读内存中。
- 防止程序员写入变量
例如,考虑这个简单函数:
int sum(const int *values, size_t length) {
register int acc = 0;
for (size_t i = 0; i < length; ++i) {
acc += values[i];
}
return acc;
}
程序员编写了register
以使累加器远离堆栈,避免每次更新时写入内存。 如果实现更改为如下所示的内容:
// Defined in some other translation unit
void add(int *dest, int src);
int sum(const int *values, size_t length) {
register int acc = 0;
for (size_t i = 0; i < length; ++i) {
add(&acc, values[i]);
}
return acc;
}
当acc
变量的地址用于add()
调用时,该变量不能再存储在寄存器中,因为寄存器没有地址。 因此,编译器会将&acc
标记为错误,让您知道您可能通过阻止acc
存在于寄存器中而破坏了代码的性能。
这在早期更为重要,当时编译器比较笨,整个函数的变量将存在于一个地方。 如今,变量的大部分生命周期都可以在寄存器中度过,只有在获取其地址时才暂时移动到堆栈上。 也就是说,这段代码:
/* Passed by reference for some reason. */
void debug(const int *value);
int sum(const int *values, size_t length) {
int acc = 0;
for (size_t i = 0; i < length; ++i) {
acc += values[i];
}
debug(&acc);
return acc;
}
会导致acc
在旧编译器中整个函数的堆栈上生存。 现代编译器会将acc
保存在寄存器中,直到debug()
调用之前。
现代 C 代码通常不使用register
关键字。
C99 Rationale提供了更多关键字register
的上下文:
国际标准的基本原理 — 编程语言 — C
§6.7.1 存储类说明符
由于无法获取
register
变量的地址,因此存储类的对象register
有效地存在于与其他对象不同的空间中。(函数占用第三个地址空间。这使它们成为最佳放置的候选者,这是宣布登记册的通常原因;但这也使它们成为更积极的优化的候选者。
- Visual Studio 2015:Extern "C" 和 "export" 关键字
- C++中的"inline"关键字
- 如何确保C++函数在定义之前声明(如override关键字)
- 无法将结构注册为增强几何体3D点
- 如何使用AngelScript注册SFML Vector2运算符
- 在遍历处理程序的向量时注册和注销处理程序
- 有没有任务栏API可以立即应用注册表更改
- 使用QJsEngine在Qt中注册自定义类型
- 谷歌模拟和覆盖关键字
- 检查注册表项是否链接到(或副本)另一个注册表项
- 结构体 S { int align; } 之间的区别;(struct 关键字后的名称)和 struct { int al
- 如果全局变量默认是外部变量,为什么要添加"extern"关键字?
- 如何使用 TStyleManager::UnRegisterStyle() 取消注册样式
- 当我从下面的代码中删除关键字 virtual 时,它可以正常工作,否则会出现错误。在这里"virtual"字的意义是什么?
- 为什么"delete"关键字不删除节点?
- WINAPI 注册应用程序重新启动时不清除打开的套接字
- SFML 碰撞永远不会在我的系统中注册
- 为什么创建注册关键字
- 注册关键字是否仍在使用
- QtCreator:如何将"override"和"final"注册为关键字?