如果不使用结果值,i++和++i之间是否有性能差异?
当前回答
我已经阅读了这里的大部分答案和许多评论,我没有看到任何一个我能想到的实例,在哪里i++比++ I更有效(也许令人惊讶的是- I比I更有效)。这是针对DEC PDP-11的C编译器!
PDP-11的汇编指令用于寄存器的前减和后增,但没有相反的指令。这些指令允许任何“通用”寄存器用作堆栈指针。所以如果你使用像*(i++)这样的东西,它可以被编译成一个汇编指令,而*(++i)不能。
这显然是一个非常深奥的例子,但它确实提供了后增量更有效的例外(或者我应该说曾经,因为现在对PDP-11 C代码的需求并不多)。
其他回答
执行摘要:没有。
i++可能比++ I慢,因为I的旧值 可能需要保存以备以后使用,但实际上都是现代的 编译器将对其进行优化。
我们可以通过查看这个函数的代码来证明这一点, 都是++i和i++。
$ cat i++.c
extern void g(int i);
void f()
{
int i;
for (i = 0; i < 100; i++)
g(i);
}
文件是一样的,除了++i和i++:
$ diff i++.c ++i.c
6c6
< for (i = 0; i < 100; i++)
---
> for (i = 0; i < 100; ++i)
我们将编译它们,并获得生成的汇编器:
$ gcc -c i++.c ++i.c
$ gcc -S i++.c ++i.c
我们可以看到生成的对象和汇编程序文件都是相同的。
$ md5 i++.s ++i.s
MD5 (i++.s) = 90f620dda862cd0205cd5db1f2c8c06e
MD5 (++i.s) = 90f620dda862cd0205cd5db1f2c8c06e
$ md5 *.o
MD5 (++i.o) = dd3ef1408d3a9e4287facccec53f7d22
MD5 (i++.o) = dd3ef1408d3a9e4287facccec53f7d22
摘自Andrew Koenig的《效率与意图》:
首先,++i是否比i++更有效还不明显,至少在涉及整型变量时是这样。
和:
所以人们应该问的问题不是这两种操作中哪一种更快,而是这两种操作中哪一种更准确地表达了你想要完成的事情。我认为,如果你不使用表达式的值,永远没有理由使用i++而不是++ I,因为永远没有理由复制一个变量的值,增加变量,然后扔掉拷贝。
因此,如果没有使用结果值,则使用++ I。但不是因为它更有效,而是因为它正确地表达了我的意图。
我总是喜欢预增量,然而……
我想指出的是,即使在调用运算符++函数的情况下,如果函数得到内联,编译器将能够优化掉临时函数。由于操作符++通常很短,并且经常在头文件中实现,因此它很可能被内联。
因此,出于实际目的,这两种形式的性能之间可能没有太大差异。然而,我总是喜欢预增量,因为它似乎更好地直接表达我想说的,而不是依赖于优化器来解决它。
此外,给优化器更少的任务可能意味着编译器运行得更快。
更好的答案是++i有时会更快,但绝不会变慢。
每个人似乎都认为i是一个常规的内置类型,比如int。在这种情况下,将没有可测量的差异。
然而,如果i是复型,那么你很可能会发现一个可测量的差异。对于i++,您必须在递增类之前复制它。根据复制中涉及的内容,它确实可能会变慢,因为使用++i可以只返回最终值。
Foo Foo::operator++()
{
Foo oldFoo = *this; // copy existing value - could be slow
// yadda yadda, do increment
return oldFoo;
}
另一个区别是,使用++i,您可以选择返回一个引用而不是一个值。同样,根据复制对象所涉及的内容,这可能会更慢。
在现实世界中,迭代器的使用就是可能发生这种情况的一个例子。复制迭代器不太可能成为应用程序中的瓶颈,但养成使用++i而不是i++的习惯仍然是一个很好的实践,因为i++的结果不会受到影响。
我的C有点生疏了,所以我提前道歉。就速度而言,我可以理解结果。但是,我对这两个文件是如何得到相同的MD5哈希感到困惑。也许for循环也可以运行,但是下面两行代码不会生成不同的程序集吗?
myArray[i++] = "hello";
vs
myArray[++i] = "hello";
第一个函数将值写入数组,然后将i加1,第二个函数将i加1,然后将值写入数组。我不是汇编专家,但我只是不明白这两行不同的代码如何生成相同的可执行文件。
这只是我的个人意见。