我们的问题是,在C语言中i++和++i的性能有区别吗?

c++的答案是什么?


当前回答

两者都一样快;) 如果你想在处理器上进行相同的计算,只是计算的顺序不同。

例如,以下代码:

#include <stdio.h>

int main()
{
    int a = 0;
    a++;
    int b = 0;
    ++b;
    return 0;
}

生产以下组件:

0x0000000100000f24 <main+0>: push %rbp 0x0000000100000f25 <main+1>: mov %rsp,%rbp 0x0000000100000f28 <main+4>: movl $0x0,-0x4(%rbp) 0x0000000100000f2f <main+11>: incl -0x4(%rbp) 0x0000000100000f32 <main+14>: movl $0x0,-0x8(%rbp) 0x0000000100000f39 <main+21>: incl -0x8(%rbp) 0x0000000100000f3c <main+24>: mov $0x0,%eax 0x0000000100000f41 <main+29>: leaveq .日志含义 0x0000000100000f42 <main+30>: retq

你可以看到,对于a++和b++,它是一个包含助记符,所以它是相同的操作;)

其他回答

@wilhelmtell

编译器可以省略临时对象。从另一个线程逐字逐句:

c++编译器允许消除基于堆栈的临时对象,即使这样做会改变程序行为。MSDN链接vc8:

http://msdn.microsoft.com/en-us/library/ms364057 (VS.80) . aspx

说编译器不能优化掉后缀情况下的临时变量副本是不完全正确的。用VC进行的快速测试表明,至少在某些情况下,它可以做到这一点。

在下面的例子中,生成的代码对于前缀和后缀是相同的,例如:

#include <stdio.h>

class Foo
{
public:

    Foo() { myData=0; }
    Foo(const Foo &rhs) { myData=rhs.myData; }

    const Foo& operator++()
    {
        this->myData++;
        return *this;
    }

    const Foo operator++(int)
    {
        Foo tmp(*this);
        this->myData++;
        return tmp;
    }

    int GetData() { return myData; }

private:

    int myData;
};

int main(int argc, char* argv[])
{
    Foo testFoo;

    int count;
    printf("Enter loop count: ");
    scanf("%d", &count);

    for(int i=0; i<count; i++)
    {
        testFoo++;
    }

    printf("Value: %d\n", testFoo.GetData());
}

无论您使用的是++testFoo还是testfoo++,都将得到相同的结果代码。事实上,无需从用户读取计数,优化器将整个事情归结为一个常数。所以这个:

for(int i=0; i<10; i++)
{
    testFoo++;
}

printf("Value: %d\n", testFoo.GetData());

结果如下:

00401000  push        0Ah  
00401002  push        offset string "Value: %d\n" (402104h) 
00401007  call        dword ptr [__imp__printf (4020A0h)] 

因此,虽然后缀版本肯定会更慢,但如果你不使用它,优化器可能会足够好,可以摆脱临时副本。

@Ketan

...加薪忽略了关于意图和性能的细节。有时我们想用iter++而不是++iter。

Obviously post and pre-increment have different semantics and I'm sure everyone agrees that when the result is used you should use the appropriate operator. I think the question is what should one do when the result is discarded (as in for loops). The answer to this question (IMHO) is that, since the performance considerations are negligible at best, you should do what is more natural. For myself ++i is more natural but my experience tells me that I'm in a minority and using i++ will cause less metal overhead for most people reading your code.

毕竟,这就是语言不叫“c++ C”的原因。[*]

[*]插入关于c++ C是一个更合乎逻辑的名称的必要讨论。

++i比i++快,因为它不返回值的旧副本。

它也更直观:

x = i++;  // x contains the old value of i
y = ++i;  // y contains the new value of i 

这个C语言的例子输出的是“02”而不是你所期望的“12”:

#include <stdio.h>

int main(){
    int a = 0;
    printf("%d", a++);
    printf("%d", ++a);
    return 0;
}

c++也是一样:

#include <iostream>
using namespace std;

int main(){
    int a = 0;
    cout << a++;
    cout << ++a;
    return 0;
}

有意的问题是关于什么时候结果是未使用的(这从C的问题中很明显)。有人能解决这个问题吗,因为这个问题是“社区维基”?

关于过早优化,Knuth经常被引用。这是正确的。但是Donald Knuth永远不会用你现在看到的那些可怕的代码来辩护。见过Java整数(不是int)中的a = b + c吗?这相当于3次装箱/开箱转换。避免这样的事情很重要。无用地写i++而不是++i也是同样的错误。 编辑:正如phresnel在评论中所言,这可以总结为“过早的优化是邪恶的,过早的悲观也是”。

甚至人们更习惯于i++这一事实也是一个不幸的C遗产,是由K&R的一个概念错误造成的(如果你遵循意图论点,这是一个合乎逻辑的结论;为K&R辩护因为他们是K&R是毫无意义的,他们很伟大,但作为语言设计师他们并不伟大;C设计中存在无数错误,从gets()到strcpy(),再到strncpy() API(它应该从第一天开始就有strlcpy() API)。

顺便说一句,我是那些不太习惯c++的人之一,觉得c++ I读起来很烦人。尽管如此,我仍然使用它,因为我承认它是正确的。