我为我制作的DSP /音频应用程序编写了这个基本代码:
double input = 0.0;
for (int i = 0; i < nChannels; i++) {
input = inputs[i];
并且一些DSP工程专家告诉我: &#34;你不应该在循环之外声明它,否则它会创建一个依赖项,编译器不能像它一样有效地处理它可能&#34;
我认为他正在谈论var input
。为什么这个?是不是一次更好的去除并覆盖它?
也许有些事情与使用不同的内存位置有关?即注册而不是堆栈?
答案 0 :(得分:7)
80年代早期的旧K&amp; R C编译器过去常常编写程序员编写的代码,程序员过去常常尽力生成优化的源代码。现代优化编译器可以返工,只要生成的代码与原始代码具有相同的可观察效果 。因此,假设input
变量未在循环外使用,优化编译器可以优化行double input = 0.0;
,因为在下一次分配之前没有可观察到的影响:input = inputs[i];
。并且它可能与循环外的变量赋值相同(无论是在源C ++文件中它是否在内部)也是出于同样的原因。
简短的故事,除非你想为一个具有一个特定参数集的特定编译器生成代码,在这种情况下你应该彻底检查生成的汇编代码,你永远不应该担心那些低级优化。有人说编译器比你更聪明,其他人说编译器会以我编写的方式生成自己的代码。
重要的是可读性和可变范围。这里input
是循环的本地函数,因此它应该在循环内声明。完全停止。任何其他优化考虑都是无用的,除非您对低级优化有特殊要求(分析显示这些行需要特殊处理)。
答案 1 :(得分:3)
最好在循环中声明变量,但原因是错误的。
有一条经验法则:在尽可能小的范围内声明变量。您的代码更具可读性且不易出错。
至于性能问题,对于任何正确声明变量的现代编译器来说,它都没有关系。例如,clang
完全取消了-O1
变量与其自己的IR:https://godbolt.org/g/yjs4dA
然而,如果您使用地址input
,变量can't be eliminated(轻松),并且您应该在循环中声明它,如果您关心性能。
答案 2 :(得分:3)
许多人认为声明变量会为您分配一些内存供您使用。它不像那样工作。它也没有分配寄存器。
它只会为您创建一个名称(和关联类型),您可以使用该名称将值的使用者与其生产者联系起来。
在一个50岁的编译器(或学生在他们的第三年编译器构建课程中编写的编译器)中,可以通过为堆栈上的变量分配一些内存来实现,并且每次引用变量时都使用它。它很简单,有效,而且效率极低。一个好的进步就是在可能的情况下将局部变量放在寄存器中,但是使用寄存器的效率低,并且它不是我们目前所处的位置(已经有一段时间了)。
将消费者与生产者联系起来可创建数据流图。在大多数现代编译器中,它是接收寄存器的图中的边缘。在您声明它们时,这将从任何变量中完全删除。它们不再存在。如果你在clang中使用-emit-llvm,你可以看到这个。
因此变量不是真实的,它们只是标签。根据需要使用它们。