C 在现代编译器中进行优化时,使用“register”关键字没有用吗?

C 在现代编译器中进行优化时,使用“register”关键字没有用吗?,c,gcc,visual-c++,clang,C,Gcc,Visual C++,Clang,Cregister关键字提示编译器更喜欢将变量存储在寄存器中,而不是堆栈上。如果编译器愿意,可以忽略它。我知道现在当你在编译时打开了优化功能,它基本上是无用的,但是它完全是无用的吗 更具体地说:对于{gcc,clang,msvc}x{-Og,-O,-O2,-O3}的任何组合:寄存器在决定是否实际分配寄存器时是否被忽略?如果没有,在某些情况下,它是否有用到可以麻烦地使用它 注意事项: 我不是问这个关键词是否有任何效果;当然,它会阻止您使用该变量的地址;如果您根本不优化,它将使变量的寄存器分配或内

C
register
关键字提示编译器更喜欢将变量存储在寄存器中,而不是堆栈上。如果编译器愿意,可以忽略它。我知道现在当你在编译时打开了优化功能,它基本上是无用的,但是它完全是无用的吗

更具体地说:对于{gcc,clang,msvc}x{-Og,-O,-O2,-O3}的任何组合:
寄存器在决定是否实际分配寄存器时是否被忽略?如果没有,在某些情况下,它是否有用到可以麻烦地使用它

注意事项:

  • 我不是问这个关键词是否有任何效果;当然,它会阻止您使用该变量的地址;如果您根本不优化,它将使变量的寄存器分配或内存分配有所不同
  • 只需回答一个编译器/上面的一些组合就可以了

对于GCC,
寄存器
对于所有支持的CPU体系结构,在所有优化级别上,十多年来对代码生成没有任何影响,甚至没有任何提示

这主要是历史原因造成的。GCC 2.95及更早版本有两个寄存器分配器,一个在未优化时使用(“愚蠢”),另一个在优化时使用(“本地、全局、重新加载”)。“愚蠢的”分配器确实试图尊重
寄存器
,但“本地、全局、重新加载”分配器完全忽略了它。(我不知道这个设计决策的最初理由是什么;你得问问理查德·肯纳。)在3.0版中,“愚蠢”的分配器被废弃了,取而代之的是在“本地、全局、重新加载”中添加一个快速、草率的模式。没有人费心编写代码来让该模式注意
寄存器
,所以它没有

在撰写本文时,GCC开发人员正在用一个名为“IRA和LRA”的新分配器替换“本地、全局、重新加载”,但它也完全忽略了寄存器


但是,您不能获取
寄存器
变量地址的(仅C)规则仍然强制执行,并且关键字由使用,这允许您将特定寄存器专用于变量;这在使用大量内联汇编的程序中非常有用。

对于GCC,
寄存器对于所有支持的CPU体系结构,在所有优化级别上,十多年来对代码生成没有任何影响,甚至没有任何提示

这主要是历史原因造成的。GCC 2.95及更早版本有两个寄存器分配器,一个在未优化时使用(“愚蠢”),另一个在优化时使用(“本地、全局、重新加载”)。“愚蠢的”分配器确实试图尊重
寄存器
,但“本地、全局、重新加载”分配器完全忽略了它。(我不知道这个设计决策的最初理由是什么;你得问问理查德·肯纳。)在3.0版中,“愚蠢”的分配器被废弃了,取而代之的是在“本地、全局、重新加载”中添加一个快速、草率的模式。没有人费心编写代码来让该模式注意
寄存器
,所以它没有

在撰写本文时,GCC开发人员正在用一个名为“IRA和LRA”的新分配器替换“本地、全局、重新加载”,但它也完全忽略了寄存器

但是,您不能获取
寄存器
变量地址的(仅C)规则仍然强制执行,并且关键字由使用,这允许您将特定寄存器专用于变量;这在使用大量内联汇编的程序中非常有用。

C标准说明:

(c11,6.7.1p6)“使用存储类说明符寄存器声明对象的标识符表明可以尽快访问该对象。此类建议的有效程度由实现定义。”

实现定义的这些建议意味着实现必须定义所做的选择((c11,J.3.8提示)“使用寄存器存储类说明符提出的建议的有效程度(6.7.1)”

下面是一些流行的C编译器的文档说明

对于
gcc
():

寄存器说明符仅以以下方式影响代码生成:

  • 当用作寄存器变量扩展的一部分时,请参阅显式寄存器变量

  • 当使用-O0时,编译器为所有没有寄存器存储类的变量分配不同的堆栈内存 说明符;如果指定了寄存器,则变量可能具有 比代码指示的寿命更短,并且可能永远不会 放在记忆里

  • 在一些罕见的x86目标上,setjmp并不是在所有情况下都保存寄存器。在这些情况下,GCC不分配任何 寄存器中的变量,除非它们标记为寄存器
对于
IAR
ARM()编译器:

遵守注册表关键字(6.7.1)

不接受用户对注册表变量的请求

C标准规定:

(c11,6.7.1p6)“使用存储类说明符寄存器声明对象的标识符表明可以尽快访问该对象。此类建议的有效程度由实现定义。”

实现定义的这些建议意味着实现必须定义所做的选择((c11,J.3.8提示)“使用寄存器存储类说明符提出的建议的有效程度(6.7.1)”

下面是一些流行的C编译器的文档说明

对于
gcc
():

寄存器说明符仅以以下方式影响代码生成:

  • 当用作寄存器变量扩展的一部分时,请参阅显式寄存器变量

  • <
    void test(int *somePointer)
    {
      int i;
      for (int i=0; i<10; i+=2)
      {
        somePointer[i] = -1;
        somePointer[i+1] = 2;
    
    {
      int temp = i;
      get_integer(&temp);
      i = temp;
    }