【问题标题】:when to use registers in C?何时在 C 中使用寄存器?
【发布时间】:2011-01-05 08:08:05
【问题描述】:

我有这样的事情

register unsigned int a, b, c;
int n;
for (n = 0; n < 10; ++n){
c = a + b
b = a
a = c
array[n] = c;
}

它做什么,没关系。代码以现在的方式运行得很快,如果删除了 register 关键字,则运行得更慢。但是,当我在 int n 之前添加寄存器时,它实际上运行速度比现在慢,但比不使用寄存器时快。

谁能给我解释一下?谢谢。

【问题讨论】:

  • 目标架构有多少个通用寄存器?还有,什么编译器?
  • 您是否在编译时启用了完全优化(例如-O3)?大多数编译器的优化,包括寄存器分配,默认是禁用的。这使得调试构建的任何时间安排(在 -O 上编译时没有一些变体)都毫无意义。
  • 例如,一种可能性是(使用足够的优化标志)您的编译器更愿意完全优化 n,而是通过推进表示 array+n 的指针来循环。也许它会注意您的 register 关键字,将 n 放入寄存器中并且(因此)不会进行它想要的优化。 但是它的作用很重要 - (1) 它正在生成斐波那契数,所以它是一个小循环,所以我会怀疑任何时间。 (2) a 和 b 没有被初始化,所以优化器基本上可以做它喜欢的事情,并且(因此)产生不可行的快速、损坏的代码。
  • 哦,array+n 更快的原因(如果确实如此)可能与寻址模式有关,也可能是因为它使用较少的寄存器,如果你强制额外的寄存器你会在循环中得到堆栈溢出。无论如何,有些这样的事情 - 这段代码很简单,如果你只看两个不同版本的反汇编,你可能会明白为什么较慢的版本更慢。

标签: c cpu-registers


【解决方案1】:

register 提示编译器将变量放入寄存器而不是内存/堆栈空间。在某些情况下,您放置此关键字的每个变量都没有足够的寄存器,因此将其放置在太多变量上可能会再次迫使其他一些变量退出寄存器。

不过,这只是一个提示,编译器不必接受它。

【讨论】:

  • 这也意味着你不能通过地址传递变量——或者不应该这样做,因为寄存器中的变量没有地址。
  • 通过地址传递register 变量只是告诉编译器将其溢出到堆栈。在 C++(但不是 ANSI C)中它是完全合法的。
  • 请注意,有时芯片上没有足够的寄存器可用。您只需 request 程序使用注册。它可能不会使用它。
【解决方案2】:

你是怎么计时的?在实践中,register 通常什么都不做。当编译器技术非常原始并且编译器无法自己弄清楚寄存器分配时,这是一件很糟糕的事情。它应该是为该变量分配寄存器的提示,并且对于经常使用的变量很有用。如今,大多数编译器只是忽略它并根据自己的算法分配寄存器。

【讨论】:

  • 我听说很多地方都忽略了这个标志,但除了谣言之外,我从未见过任何支持这一点的东西。你碰巧有资源吗?根据我使用 gcc 的经验,这个标志有时会产生影响(尽管我承认差异通常是负面的)。
  • @soap dsimcha 是对的,它是过去的遗迹。 wiki it google it 等等——你会找到你的证明。
  • 关闭优化后 gcc 会有所不同(参考:gcc.gnu.org/onlinedocs/gcc/Hints-implementation.html)。
  • 虽然你会想知道为什么在没有优化的情况下编译时你要尝试使用register“优化”。
【解决方案3】:

可用的寄存器数量有限,因此将所有内容标记为寄存器不会将所有内容都放入寄存器中。基准测试是知道它是否有用的唯一方法。一个好的编译器应该能够自行确定将哪些变量放入寄存器,因此您可能应该在确定寄存器关键字有帮助之前进行更多基准测试。

【讨论】:

  • “基准测试是了解它是否有用的唯一方法”。好吧,他说他已经进行了基准测试,并且针对三种不同的情况得出了结果。如果他的基准不正确,那么告诉他再次进行基准测试不会使它们正确;-)
  • 这似乎很奇怪,因为优化编译器应该知道哪些变量应该进入寄存器,所以我认为再次进行基准测试以确保它正确完成是明智的。
【解决方案4】:

可分配的寄存器是有限制的。如果你放弃它,你最终会得到效率较低的代码。

我的看法是,如果你所做的事情如此重要,以至于你必须自己决定什么进入寄存器,什么不进入,你应该使用汇编语言来编写它。

对于通用语言,我坚信编译器比人类更能决定寄存器中的内容。证明是,虽然您不确定可以在寄存器中放入多少变量,但您的编译器肯定知道。

【讨论】:

    【解决方案5】:

    在 gcc 中,寄存器绝对不会被忽略,除非你指定优化选项。 用这样的东西测试你的代码

    unsigned int array[10];
    
    int n;
    
    #define REG register
    
    int main()
    {
        REG unsigned int a, b, c;
    
        for (n = 0; n < 10; ++n){
            c = a + b;
            b = a;
            a = c;
            array[n] = c;
        }
    }
    

    您获得(取决于 REG 是否已定义或为空)

    http://picasaweb.google.com/lh/photo/v2hBpl6D-soIdBXUOmAeMw?feat=directlink

    左边是使用寄存器的结果。

    【讨论】:

    • 在什么优化级别被忽略?
    • 这取决于被优化的代码。检查在您的特定情况下生成的汇编程序。
    【解决方案6】:

    使用寄存器的想法是,您的变量被非常频繁地使用。如果您的变量有任何操作,无论如何它都会被复制到寄存器中。所以计数器(索引变量)是这个修饰符的候选者。在 2010 年 1 月 15 日 1:57 的 Diego Torres Milano 示例中,我会这样做:

    unsigned int array[10];    
    
    int main()
    {
        register int n;
        unsigned int a = 1, b = 2, c;
    
        for (n = 0; n < 10; ++n){
            c = a + b;
            b = a;
            a = c;
            array[n] = c;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-22
      • 1970-01-01
      • 2012-06-23
      • 1970-01-01
      • 2014-08-03
      • 2016-01-10
      • 2020-02-14
      • 2012-03-23
      相关资源
      最近更新 更多