如果不使用结果值,i++和++i之间是否有性能差异?
当前回答
摘自Andrew Koenig的《效率与意图》:
首先,++i是否比i++更有效还不明显,至少在涉及整型变量时是这样。
和:
所以人们应该问的问题不是这两种操作中哪一种更快,而是这两种操作中哪一种更准确地表达了你想要完成的事情。我认为,如果你不使用表达式的值,永远没有理由使用i++而不是++ I,因为永远没有理由复制一个变量的值,增加变量,然后扔掉拷贝。
因此,如果没有使用结果值,则使用++ I。但不是因为它更有效,而是因为它正确地表达了我的意图。
其他回答
参考Scott Meyers的《更有效的c++第六条:区分增减操作的前缀和后缀形式》。
对于对象,尤其是对于迭代器,前缀版本总是优于后缀版本。
原因是,如果你看一下操作符的调用模式。
// Prefix
Integer& Integer::operator++()
{
*this += 1;
return *this;
}
// Postfix
const Integer Integer::operator++(int)
{
Integer oldValue = *this;
++(*this);
return oldValue;
}
看看这个例子,很容易看出前缀操作符总是比后缀操作符更有效率。因为需要在临时对象中使用后缀。
这就是为什么当你看到使用迭代器的例子时,他们总是使用前缀版本。
但正如你所指出的,对于int型,实际上没有什么区别,因为编译器优化可以发生。
我已经阅读了这里的大部分答案和许多评论,我没有看到任何一个我能想到的实例,在哪里i++比++ I更有效(也许令人惊讶的是- I比I更有效)。这是针对DEC PDP-11的C编译器!
PDP-11的汇编指令用于寄存器的前减和后增,但没有相反的指令。这些指令允许任何“通用”寄存器用作堆栈指针。所以如果你使用像*(i++)这样的东西,它可以被编译成一个汇编指令,而*(++i)不能。
这显然是一个非常深奥的例子,但它确实提供了后增量更有效的例外(或者我应该说曾经,因为现在对PDP-11 C代码的需求并不多)。
在C语言中,如果结果未被使用,编译器通常可以将它们优化为相同。
然而,在c++中,如果使用提供自己的++操作符的其他类型,前缀版本可能比后缀版本更快。因此,如果不需要后缀语义,最好使用前缀操作符。
简短的回答:
i++和++i在速度上没有任何区别。一个好的编译器不应该在这两种情况下生成不同的代码。
长一点的回答:
其他答案都没有提到的是,++i和i++之间的区别只在它所找到的表达式中有意义。
对于for(i=0;我< n;i++), i++在它自己的表达式中是单独的:在i++之前有一个序列点,在它之后有一个。因此,生成的唯一机器码是“将i增加1”,并且它是如何与程序的其余部分进行排序的。所以如果你把它改成前缀++,这一点关系都没有,你仍然会得到机器代码“将i增加1”。
++i和i++之间的差异只在数组[i++] = x;与数组[++i] = x;有些人可能会争辩说,后缀在这样的操作中会更慢,因为i所在的寄存器稍后必须重新加载。但是请注意,编译器可以自由地以任何它喜欢的方式对你的指令进行排序,只要它不像C标准所说的那样“破坏抽象机器的行为”。
所以当你假设数组[i++] = x;被翻译成机器代码为:
将i的值存储在寄存器A中。 存储寄存器B中数组的地址。 将A和B相加,将结果存储在A中。 在这个由A表示的新地址上,存储x的值。 在寄存器A //中存储i的值是低效的,因为这里有额外的指令,我们已经做过一次了。 增量寄存器A。 在i中存储寄存器A。
编译器也可以更有效地生成代码,例如:
将i的值存储在寄存器A中。 存储寄存器B中数组的地址。 添加A和B,将结果存储在B中。 增量寄存器A。 在i中存储寄存器A。 ... //其余的代码。
只是因为作为一个C程序员,你被训练成认为后缀++发生在结尾,所以机器代码不需要以这种方式排序。
所以在C语言中,前缀++和后缀++没有区别。现在,作为一个C程序员,你应该知道的是,有些人在某些情况下不一致地使用前缀,而在其他情况下不一致地使用后缀,没有任何理由。这表明他们不确定C语言是如何工作的,或者他们对这门语言的了解不正确。这总是一个不好的迹象,它反过来表明他们在他们的程序中做出了其他有问题的决定,基于迷信或“宗教教条”。
“前缀++总是更快”确实是一个错误的教条,在准C程序员中很常见。
首先:在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.
推荐文章
- 如何将文件指针(file * fp)转换为文件描述符(int fd)?
- 如何加速gwt编译器?
- MySQL OR与IN性能
- 应该……接住环内还是环外?
- 哪个更快/最好?SELECT *或SELECT columnn1, colum2, column3等
- C“int”的大小是2字节还是4字节?
- 加快R中的循环操作
- 多维数组如何在内存中格式化?
- printf()和puts()在C语言中的区别是什么?
- 断言是邪恶的吗?
- INT和VARCHAR主键之间有真正的性能差异吗?
- 在Java中使用“final”修饰符
- 有效,但毫无价值的语法在开关情况下?
- c++标准是否要求iostreams的性能很差,或者我只是在处理一个糟糕的实现?
- 我怎么知道什么时候创建一个接口?