C++中的注册关键字

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3207018/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 12:19:41  来源:igfitidea点击:

Register keyword in C++

c++

提问by dato datuashvili

What is difference between

有什么区别

int x=7;

and

register int x=7;

?

?

I am using C++.

我正在使用 C++。

采纳答案by supercat

In C++ as it existed in 2010, any program which is valid that uses the keywords "auto" or "register" will be semantically identical to one with those keywords removed (unless they appear in stringized macros or other similar contexts). In that sense the keywords are useless for properly-compiling programs. On the other hand, the keywords might be useful in certain macro contexts to ensure that improper usage of a macro will cause a compile-time error rather than producing bogus code.

在 2010 年存在的 C++ 中,任何使用关键字“auto”或“register”的有效程序在语义上将与删除这些关键字的程序相同(除非它们出现在字符串化宏或其他类似上下文中)。从这个意义上说,关键字对于正确编译程序是无用的。另一方面,关键字在某些宏上下文中可能很有用,以确保宏的不当使用将导致编译时错误,而不是产生虚假代码。

In C++11 and later versions of the language, the autokeyword was re-purposed to act as a pseudo-type for objects which are initialized, which a compiler will automatically replace with the type of the initializing expression. Thus, in C++03, the declaration: auto int i=(unsigned char)5;was equivalent to int i=5;when used within a block context, and auto i=(unsigned char)5;was a constraint violation. In C++11, auto int i=(unsigned char)5;became a constraint violation while auto i=(unsigned char)5;became equivalent to auto unsigned char i=5;.

在该语言的 C++11 和更高版本中,auto关键字被重新用作已初始化对象的伪类型,编译器将自动替换为初始化表达式的类型。因此,在 C++03 中,声明:auto int i=(unsigned char)5;相当于int i=5;在块上下文中使用时,并且auto i=(unsigned char)5;是违反约束的。在 C++11 中,auto int i=(unsigned char)5;变成了约束冲突,而auto i=(unsigned char)5;变成等价于auto unsigned char i=5;.

回答by Tom

registeris a hint to the compiler, advising it to store that variable in a processor register instead of memory (for example, instead of the stack).

register是对编译器的提示,建议它将该变量存储在处理器寄存器中而不是内存中(例如,而不是堆栈中)。

The compiler may or may not follow that hint.

编译器可能会也可能不会遵循该提示。

According to Herb Sutter in "Keywords That Aren't (or, Comments by Another Name)":

根据 Herb Sutter 在“不是的关键字(或其他名称的评论)”中的说法:

A register specifier has the same semantics as an auto specifier...

寄存器说明符与自动说明符具有相同的语义...

回答by Fred Larson

According to Herb Sutter, registeris "exactly as meaningful as whitespace" and has no effect on the semantics of a C++ program.

根据Herb Sutter 的说法,register与空格完全一样有意义”并且对 C++ 程序的语义没有影响。

回答by KeithB

With today's compilers, probably nothing. Is was orginally a hint to place a variable in a register for faster access, but most compilers today ignore that hint and decide for themselves.

使用今天的编译器,可能什么都没有。最初是一个将变量放在寄存器中以加快访问速度的提示,但今天大多数编译器忽略该提示并自行决定。

回答by James Curran

Almost certainly nothing.

几乎可以肯定没有。

registeris a hint to the compiler that you plan on using xa lot, and that you think it should be placed in a register.

register是对编译器的提示,您计划x大量使用,并且您认为应该将其放置在寄存器中。

However, compilers are now far better at determining what values should be placed in registers than the average (or even expert) programmer is, so compilers just ignore the keyword, and do what they wants.

然而,编译器现在比普通(甚至专家)程序员更能确定应该将哪些值放置在寄存器中,因此编译器只需忽略关键字,然后做他们想做的事。

回答by ncomputers

The registerkeyword was useful for:

register关键字适用于:

  • Inline assembly.
  • Expert C/C++ programming.
  • Cacheable variables declaration.
  • 内联组装。
  • 专家 C/C++ 编程。
  • 可缓存变量声明。

An example of a productive system, where the registerkeyword was required:

register需要关键字的生产系统示例:

typedef unsigned long long Out;
volatile Out out,tmp;
Out register rax asm("rax");
asm volatile("rdtsc":"=A"(rax));
out=out*tmp+rax;

It has been deprecated since C++11 and is unused and reserved in C++17.

它自 C++11 起已被弃用,在C++17 中未使用和保留。

回答by usr1234567

registeris deprecated in C++11. It is unused and reserved in C++17.

register在 C++11 中已弃用。它在 C++17 中未使用并保留。

Source: http://en.cppreference.com/w/cpp/keyword/register

来源:http: //en.cppreference.com/w/cpp/keyword/register

回答by SmugLispWeenie

Consider a case when compiler's optimizer has two variables and is forced to spill one onto stack. It so happened that both variables have the same weight to the compiler. Given there is no difference, the compiler will arbitrarily spill one of the variables. On the other hand, the registerkeyword gives compiler a hint which variable will be accessed more frequently. It is similar to x86 prefetch instruction, but for compiler optimizer.

考虑编译器的优化器有两个变量并被迫将一个溢出到堆栈上的情况。碰巧这两个变量对编译器具有相同的权重。鉴于没有区别,编译器将任意溢出变量之一。另一方面,register关键字给编译器一个提示,哪个变量将被更频繁地访问。它类似于 x86 预取指令,但用于编译器优化器。

Obviously registerhints are similar to user-provided branch probability hints, and can be inferred from these probability hints. If compiler knows that some branch is taken often, it will keep branch related variables in registers. So I suggest caring more about branch hints, and forgetting about register. Ideally your profiler should communicate somehow with the compiler and spare you from even thinking about such nuances.

显然register提示类似于用户提供的分支概率提示,可以从这些概率提示中推断出来。如果编译器知道某个分支经常被占用,它就会将与分支相关的变量保存在寄存器中。所以我建议更多地关注分支提示,而忘记register. 理想情况下,您的分析器应该以某种方式与编译器进行通信,并使您无需考虑这些细微差别。

回答by Lewis Kelsey

As of gcc 9.3, compiling using -std=c++2a,registerproduces a compiler warning, but it still has the desired effect and behaves identically to C's registerwhen compiling without -O1–-Ofast optimisation flags in the respect of thisanswer. Using clang++-7 causes a compiler error however. So yes, registeroptimisations only make a difference on standard compilation with no optimisation -O flags, but they're basic optimisations that the compiler would figure out even with -O1.

由于GCC 9.3,使用编译-std=c++2aregister生成编译器警告,但它仍然有预期的效果,其行为同样到C的register在尊重Ofast优化标志-没有-O1编译时这个答案。但是,使用 clang++-7 会导致编译器错误。所以是的,register优化只对没有优化 -O 标志的标准编译产生影响,但它们是基本优化,编译器即使使用 -O1 也能计算出来。

The only difference is that in C++, you are allowed to take the address of the register variable which means that the optimisation only occurs if you don't take the address of the variable or its aliases (to create a pointer) or take a reference of it in the code (only on - O0, because a reference also has an address, because it's a const pointer on the stack, which, like a pointer can be optimised off the stack if compiling using -Ofast, except they will neverappear on the stack using -Ofast, because unlike a pointer, they cannot be made volatileand their addresses cannot be taken), otherwise it will behave like you hadn't used register, and the value will be stored on the stack.

唯一的区别是,在 C++ 中,您可以获取寄存器变量的地址,这意味着只有不获取变量或其别名的地址(创建指针)或引用时才会进行优化它在代码中(仅在 -O0 上,因为引用也有地址,因为它是堆栈上的常量指针,如果使用 -Ofast 进行编译,则可以像指针一样在堆栈外进行优化,除非它们永远不会出现在堆栈上使用 -Ofast ,因为与指针不同,它们不能被创建volatile并且它们的地址不能被获取),否则它将表现得像你没有使用过register,并且值将存储在堆栈中。

On -O0, another difference is that const registeron gcc C and gcc C++ do not behave the same. On gcc C, const registerbehaves like register, because block-scope consts are not optimised on gcc. On clang C, registerdoes nothing and only constblock-scope optimisations apply. On gcc C, registeroptimisations apply but constat block-scope has no optimisation. On gcc C++, both registerand constblock-scope optimisations combine.

在 -O0 上,另一个区别是const register在 gcc C 和 gcc C++ 上的行为不同。在 gcc C 上,const register行为类似于register,因为块作用域const未在 gcc 上优化。在 clang C 上,register什么都不做,只适用const块范围优化。在 gcc C 上,register优化适用,但const在块范围内没有优化。在 gcc C++ 上,优化registerconst块范围优化相结合。

#include <stdio.h> //yes it's C code on C++
int main(void) {
  const register int i = 3;
  printf("%d", i);
  return 0;
}

int i = 3;:

int i = 3;

.LC0:
  .string "%d"
main:
  push rbp
  mov rbp, rsp
  sub rsp, 16
  mov DWORD PTR [rbp-4], 3
  mov eax, DWORD PTR [rbp-4]
  mov esi, eax
  mov edi, OFFSET FLAT:.LC0
  mov eax, 0
  call printf
  mov eax, 0
  leave
  ret

register int i = 3;:

register int i = 3;

.LC0:
  .string "%d"
main:
  push rbp
  mov rbp, rsp
  push rbx
  sub rsp, 8
  mov ebx, 3
  mov esi, ebx
  mov edi, OFFSET FLAT:.LC0
  mov eax, 0
  call printf
  mov eax, 0
  mov rbx, QWORD PTR [rbp-8] //callee restoration
  leave
  ret

const int i = 3;

const int i = 3;

.LC0:
  .string "%d"
main:
  push rbp
  mov rbp, rsp
  sub rsp, 16
  mov DWORD PTR [rbp-4], 3 //still saves to stack
  mov esi, 3 //immediate substitution
  mov edi, OFFSET FLAT:.LC0
  mov eax, 0
  call printf
  mov eax, 0
  leave
  ret

const register int i = 3;

const register int i = 3;

.LC0:
  .string "%d"
main:
  push rbp
  mov rbp, rsp
  mov esi, 3 //loads straight into esi saving rbx push/pop and extra indirection (because C++ block-scope const is always substituted immediately into the instruction)
  mov edi, OFFSET FLAT:.LC0 // can't optimise away because printf only takes const char*
  mov eax, 0 //zeroed: https://stackoverflow.com/a/6212755/7194773
  call printf
  mov eax, 0 //default return value of main is 0
  pop rbp //nothing else pushed to stack -- more efficient than leave (rsp == rbp already)
  ret

registertells the compiler to 1)store a local variable in a callee saved register, in this case rbx, and 2)optimise out stack writes if address of variable is never taken. consttells the compiler to substitute the value immediately(instead of assigning it a register or loading it from memory) and write the local variable to the stack as default behaviour. const registeris the combination of these emboldened optimisations. This is as slimline as it gets.

register告诉编译器 1) 在被调用者保存的寄存器中存储一个局部变量,在这种情况下rbx,和 2)优化堆栈写入,如果变量的地址从未被占用const告诉编译器立即替换该值(而不是为其分配寄存器或从内存中加载它)并将局部变量作为默认行为写入堆栈。const register是这些大胆优化的组合。这是非常纤细的。

Also, on gcc C and C++, registeron its own seems to create a random 16 byte gapon the stack for the first local on the stack, which doesn't happen with const register.

此外,在 gcc C 和 C++register上,它本身似乎在堆栈上为堆栈上的第一个本地创建一个随机的 16 字节间隙,这不会发生在const register.

Compiling using -Ofast however; registerhas 0 optimisation effect because if it can be put in a register or made immediate, it always will be and if it can't it won't be; conststill optimises out the load on C and C++ but at file scope only; volatilestill forces the values to be stored and loaded from the stack.

然而,使用 -Ofast 编译;register具有 0 优化效果,因为如果它可以放入寄存器或立即执行,则始终是,如果不能,则不会;const仍然优化 C 和 C++ 上的负载,但仅在文件范围内volatile仍然强制从堆栈中存储和加载值。

.LC0:
  .string "%d"
main:
  //optimises out push and change of rbp
  sub rsp, 8 //https://stackoverflow.com/a/40344912/7194773
  mov esi, 3
  mov edi, OFFSET FLAT:.LC0
  xor eax, eax //xor 2 bytes vs 5 for mov eax, 0
  call printf
  xor eax, eax
  add rsp, 8
  ret