【问题标题】:What's a good example of register variable usage in C?什么是 C 中寄存器变量使用的好例子?
【发布时间】:2010-09-23 19:41:17
【问题描述】:

我正在阅读 K&R 并来到关于寄存器变量的小部分,想知道这里的人们是否有一些很好的实践示例。

来自 K&R 中的第 4.7 节:

寄存器声明看起来像
注册 int x;
注册字符 c;

明确地说,我只是希望看到一些很酷的代码示例。我(很确定我)理解主题,所以不需要输入冗长的解释(除非你愿意)。

【问题讨论】:

    标签: c cpu-registers kernighan-and-ritchie kr-c


    【解决方案1】:

    在使用现代编译器(阅读:过去 15 年以上)时,没有很好的寄存器使用示例,因为它几乎从来没有做过任何好事,而且可能会做一些坏事。当您使用 register 时,您是在告诉编译器“我知道如何比您更好地优化我的代码”,这几乎从来没有发生过。使用 register 时可能会发生以下三种情况之一:

    • 编译器会忽略它,这很可能。在这种情况下,唯一的危害是您无法在代码中获取变量的地址。
    • 编译器会接受您的请求,因此代码运行速度较慢。
    • 编译器会接受您的请求并且代码运行得更快,这是最不可能发生的情况。

    即使一个编译器在您使用寄存器时生成更好的代码,也没有理由相信另一个编译器会做同样的事情。如果你有一些关键代码编译器优化得不够好,你最好的选择可能是使用汇编程序来处理该部分,但当然首先要进行适当的分析以验证生成的代码确实是一个问题。

    【讨论】:

    • “可能发生三件事,两件不好”?我以前在哪里听说过... ;-)
    • 请记住,编译器完全可以忽略您的建议 - 标准中没有规定必须将寄存器变量放入寄存器中。
    • 这个答案产生了很大的影响。 Vast majority of register declarations was removed from Perl code,参考这个答案。
    • 这个答案具有误导性。 register 关键字不是关于硬件寄存器,而是关于优化。它唯一的作用就是不能取这样一个变量的地址。特别是它可以用于变量的资产别名,这非常有用。
    • 这不是误导,完全是错误的。符合标准的编译器不能忽略register:获取变量的地址是无效的,它不能忽略它。这是关键字的唯一作用:生成额外的检查和错误来帮助人类
    【解决方案2】:

    总的来说,我同意Robert,但作为任何好的规则,这个规则也有例外。
    如果您在深度嵌入式系统上工作,您可能比编译器更了解如何为在特定硬件架构上的特定应用程序优化代码

    但在 99% 的情况下,罗伯茨的解释也适用于嵌入词。

    【讨论】:

    • 老实说,这看起来很像罗伯特所说的。
    • 其实你有点对。我重读了这篇文章,最后一段是澄清我想澄清的……下次我会读得更好
    【解决方案3】:

    我知道这是很久以前的事了,但这里是 heapsort 的一个子过程的实现,其中使用寄存器变量使算法更快,至少使用 gcc 4.5.2 编译代码

    inline  void max_heapify(int *H, int i){
        char OK = FALSE;
        register int l, r, max, hI;
        while(!OK){
            OK = TRUE;
            l = left(i);
            r = right(i);
            max = i;
            if(l <= H[SIZE] && H[l] > H[i]){
                max = l;
            }
            if(r <= H[SIZE] && H[r] > H[max]){
                max = r;
            }
            if(max != i){
                OK = FALSE;
                hI = H[i];
                H[i] = H[max];
                H[max] = hI;
                i = max;
            }
        }
    }
    

    我在属性之前测试了使用和不使用 register 关键字的算法,并执行它以在我的笔记本上对一个包含 50,000,000 个元素的随机数组进行排序,每个版本几次。

    寄存器的使用将堆排序时间从 ~135s 减少到 ~125s。

    我也只测试了 5,000,000 个元素,但执行次数更多。

    没有寄存器的版本从 11s 开始,但每次执行都会降低时间,直到达到 9,65s 并停止

    带寄存器的版本从 10s 开始,将时间降低到 8,80s。

    我认为这与缓存内存有关。尽管如此,寄存器似乎使算法速度更快

    由于这些变量在算法中被大量使用,通过确保它们在寄存器上而不是将这项工作留给编译器,在这种情况下会产生更好的结果。但是,它并没有改善那么多时间。

    希望 thill 对某人有所帮助,问候。

    【讨论】:

    • 为了认真对待你的基准测试,你应该提供关于你是如何编译它的信息(什么标志),你在什么平台上做的,也许还有一些关于你的架构和/或 CPU 的细节。你如何运行 max_heapify 也很重要。
    【解决方案4】:

    另一个常见的情况是在实现低级解释器时。在寄存器中保存一些状态,例如。虚拟机堆栈指针,可以显着减少内存访问并加快您的代码速度。

    有关优化示例(5.2 栈顶缓存),请参阅 vmgen — a generator of efficient virtual machine interpreters

    【讨论】:

      【解决方案5】:

      首先,寄存器变量应该用于频繁使用的变量,例如循环控制变量,以通过最小化访问时间来提高性能。在这种情况下,您只能使用并且只能注册存储说明符 喜欢,有趣(auto int a,auto int b):错误 fun (register int a,register int b) : 只运行这个 有趣(静态int a,静态int b):错误 fun (extern int a,extern int b) :error

      【讨论】:

      • 什么?! K&R 文本来自 1970 年代,因此他们的一些建议有点过时了。使用register 绝对是其中之一。
      【解决方案6】:

      这是一个需要多个答案的问题,因为有多个编码上下文:从高级语言的角度来看,中级和低级(下至汇编),因为 C 语言可以调用汇编例程。

      使用汇编而不是 C 的原因很明显是因为在开发过程中遇到了性能问题,所以是的,需要 register 关键字,但在许多情况下,它并没有按照开发人员的预期工作

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-06-15
        • 1970-01-01
        • 1970-01-01
        • 2021-07-28
        • 1970-01-01
        • 2015-01-08
        • 1970-01-01
        • 2015-10-04
        相关资源
        最近更新 更多