如果不使用结果值,i++和++i之间是否有性能差异?
当前回答
我已经阅读了这里的大部分答案和许多评论,我没有看到任何一个我能想到的实例,在哪里i++比++ I更有效(也许令人惊讶的是- I比I更有效)。这是针对DEC PDP-11的C编译器!
PDP-11的汇编指令用于寄存器的前减和后增,但没有相反的指令。这些指令允许任何“通用”寄存器用作堆栈指针。所以如果你使用像*(i++)这样的东西,它可以被编译成一个汇编指令,而*(++i)不能。
这显然是一个非常深奥的例子,但它确实提供了后增量更有效的例外(或者我应该说曾经,因为现在对PDP-11 C代码的需求并不多)。
其他回答
我的C有点生疏了,所以我提前道歉。就速度而言,我可以理解结果。但是,我对这两个文件是如何得到相同的MD5哈希感到困惑。也许for循环也可以运行,但是下面两行代码不会生成不同的程序集吗?
myArray[i++] = "hello";
vs
myArray[++i] = "hello";
第一个函数将值写入数组,然后将i加1,第二个函数将i加1,然后将值写入数组。我不是汇编专家,但我只是不明白这两行不同的代码如何生成相同的可执行文件。
这只是我的个人意见。
更好的答案是++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++的结果不会受到影响。
请不要让“哪个更快”的问题成为使用哪个的决定因素。你可能永远不会关心那么多,此外,程序员的阅读时间比机器的时间要昂贵得多。
使用任何对阅读代码的人最有意义的方法。
摘自Andrew Koenig的《效率与意图》:
首先,++i是否比i++更有效还不明显,至少在涉及整型变量时是这样。
和:
所以人们应该问的问题不是这两种操作中哪一种更快,而是这两种操作中哪一种更准确地表达了你想要完成的事情。我认为,如果你不使用表达式的值,永远没有理由使用i++而不是++ I,因为永远没有理由复制一个变量的值,增加变量,然后扔掉拷贝。
因此,如果没有使用结果值,则使用++ I。但不是因为它更有效,而是因为它正确地表达了我的意图。
首先:在C中i++和++i之间的差异是可以忽略的。
到细节。
1. 众所周知的c++问题:++i更快
在c++中,如果i是具有重载自增操作符的某种对象,则++i的效率更高。
为什么? 在++i中,对象首先递增,然后可以作为const引用传递给任何其他函数。如果表达式是foo(i++),这是不可能的,因为现在增量需要在foo()调用之前完成,但旧的值需要传递给foo()。因此,编译器被迫在对原始i执行自增操作符之前复制i。额外的构造函数/析构函数调用是不好的部分。
如上所述,这不适用于基本类型。
2. 鲜为人知的事实是:i++可能更快
如果不需要调用构造函数/析构函数,这在C中总是如此,那么++i和i++应该同样快,对吗?不。他们的速度几乎一样快,但可能有一些小的差异,这是大多数其他答案的错误理解。
How can i++ be faster? The point is data dependencies. If the value needs to be loaded from memory, two subsequent operations need to be done with it, incrementing it, and using it. With ++i, the incrementation needs to be done before the value can be used. With i++, the use does not depend on the increment, and the CPU may perform the use operation in parallel to the increment operation. The difference is at most one CPU cycle, so it is really neglegible, but it is there. And it is the other way round then many would expect.
推荐文章
- 面试问题:检查一个字符串是否是另一个字符串的旋转
- 如何将类标记为已弃用?
- 在参数数量上重载宏
- getter和setter是糟糕的设计吗?相互矛盾的建议
- 为什么更快地检查字典是否包含键,而不是捕捉异常,以防它不?
- 越界访问数组有多危险?
- 'for'循环中的后增量和前增量产生相同的输出
- 如何在父进程退出后使子进程死亡?
- 内存泄漏是否正常?
- 当启用c++ 11时,std::vector性能回归
- 使用c++ 11的“auto”可以提高性能吗?
- 如何正确比较C中的字符串?
- 你如何设计面向对象的项目?
- std::vector比普通数组慢很多吗?
- 为什么这个for循环在某些平台上退出,而在其他平台上不退出?