简体   繁体   English

C++ 中的 i++ 和 ++i 之间有性能差异吗?

[英]Is there a performance difference between i++ and ++i in C++?

We have the question is there a performance difference between i++ and ++i in C ?我们有一个问题,C 中的i++++i之间是否存在性能差异?

What's the answer for C++? C++ 的答案是什么?

[Executive Summary: Use ++i if you don't have a specific reason to use i++ .] [内容提要:使用++i ,如果你没有特别原因需要使用i++ ]

For C++, the answer is a bit more complicated.对于 C++,答案有点复杂。

If i is a simple type (not an instance of a C++ class), then the answer given for C ("No there is no performance difference") holds, since the compiler is generating the code.如果i是简单类型(不是 C++ 类的实例),则为 C 给出的答案(“不存在性能差异”)成立,因为编译器正在生成代码。

However, if i is an instance of a C++ class, then i++ and ++i are making calls to one of the operator++ functions.但是,如果i是 C++ 类的实例,则i++++i正在调用operator++函数之一。 Here's a standard pair of these functions:这是这些函数的标准对:

Foo& Foo::operator++()   // called for ++i
{
    this->data += 1;
    return *this;
}

Foo Foo::operator++(int ignored_dummy_value)   // called for i++
{
    Foo tmp(*this);   // variable "tmp" cannot be optimized away by the compiler
    ++(*this);
    return tmp;
}

Since the compiler isn't generating code, but just calling an operator++ function, there is no way to optimize away the tmp variable and its associated copy constructor.由于编译器不生成代码,而只是调用operator++函数,因此无法优化掉tmp变量及其关联的复制构造函数。 If the copy constructor is expensive, then this can have a significant performance impact.如果复制构造函数很昂贵,那么这会对性能产生重大影响。

Yes.是的。 There is.有。

The ++ operator may or may not be defined as a function. ++ 运算符可以定义为函数,也可以不定义为函数。 For primitive types (int, double, ...) the operators are built in, so the compiler will probably be able to optimize your code.对于原始类型(int、double、...),运算符是内置的,因此编译器可能能够优化您的代码。 But in the case of an object that defines the ++ operator things are different.但是对于定义 ++ 运算符的对象,情况就不同了。

The operator++(int) function must create a copy. operator++(int) 函数必须创建一个副本。 That is because postfix ++ is expected to return a different value than what it holds: it must hold its value in a temp variable, increment its value and return the temp.那是因为 postfix ++ 应该返回一个与它所保存的值不同的值:它必须将它的值保存在一个临时变量中,增加它的值并返回临时值。 In the case of operator++(), prefix ++, there is no need to create a copy: the object can increment itself and then simply return itself.在operator++(),前缀++的情况下,不需要创建副本:对象可以自增,然后简单地返回自己。

Here is an illustration of the point:这是该点的说明:

struct C
{
    C& operator++();      // prefix
    C  operator++(int);   // postfix

private:

    int i_;
};

C& C::operator++()
{
    ++i_;
    return *this;   // self, no copy created
}

C C::operator++(int ignored_dummy_value)
{
    C t(*this);
    ++(*this);
    return t;   // return a copy
}

Every time you call operator++(int) you must create a copy, and the compiler can't do anything about it.每次调用 operator++(int) 时都必须创建一个副本,编译器对此无能为力。 When given the choice, use operator++();当有选择时,使用 operator++(); this way you don't save a copy.这样你就不会保存副本。 It might be significant in the case of many increments (large loop?) and/or large objects.在许多增量(大循环?)和/或大对象的情况下,它可能很重要。

Here's a benchmark for the case when increment operators are in different translation units.这是增量运算符在不同翻译单元中的情况的基准。 Compiler with g++ 4.5.用 g++ 4.5 编译。

Ignore the style issues for now暂时忽略样式问题

// a.cc
#include <ctime>
#include <array>
class Something {
public:
    Something& operator++();
    Something operator++(int);
private:
    std::array<int,PACKET_SIZE> data;
};

int main () {
    Something s;

    for (int i=0; i<1024*1024*30; ++i) ++s; // warm up
    std::clock_t a = clock();
    for (int i=0; i<1024*1024*30; ++i) ++s;
    a = clock() - a;

    for (int i=0; i<1024*1024*30; ++i) s++; // warm up
    std::clock_t b = clock();
    for (int i=0; i<1024*1024*30; ++i) s++;
    b = clock() - b;

    std::cout << "a=" << (a/double(CLOCKS_PER_SEC))
              << ", b=" << (b/double(CLOCKS_PER_SEC)) << '\n';
    return 0;
}

O(n) increment O(n) 增量

Test测试

// b.cc
#include <array>
class Something {
public:
    Something& operator++();
    Something operator++(int);
private:
    std::array<int,PACKET_SIZE> data;
};


Something& Something::operator++()
{
    for (auto it=data.begin(), end=data.end(); it!=end; ++it)
        ++*it;
    return *this;
}

Something Something::operator++(int)
{
    Something ret = *this;
    ++*this;
    return ret;
}

Results结果

Results (timings are in seconds) with g++ 4.5 on a virtual machine:在虚拟机上使用 g++ 4.5 的结果(计时以秒为单位):

Flags (--std=c++0x)       ++i   i++
-DPACKET_SIZE=50 -O1      1.70  2.39
-DPACKET_SIZE=50 -O3      0.59  1.00
-DPACKET_SIZE=500 -O1    10.51 13.28
-DPACKET_SIZE=500 -O3     4.28  6.82

O(1) increment O(1) 增量

Test测试

Let us now take the following file:现在让我们获取以下文件:

// c.cc
#include <array>
class Something {
public:
    Something& operator++();
    Something operator++(int);
private:
    std::array<int,PACKET_SIZE> data;
};


Something& Something::operator++()
{
    return *this;
}

Something Something::operator++(int)
{
    Something ret = *this;
    ++*this;
    return ret;
}

It does nothing in the incrementation.它在增量中什么也不做。 This simulates the case when incrementation has constant complexity.这模拟了增量具有恒定复杂性的情况。

Results结果

Results now vary extremely:结果现在变化很大:

Flags (--std=c++0x)       ++i   i++
-DPACKET_SIZE=50 -O1      0.05   0.74
-DPACKET_SIZE=50 -O3      0.08   0.97
-DPACKET_SIZE=500 -O1     0.05   2.79
-DPACKET_SIZE=500 -O3     0.08   2.18
-DPACKET_SIZE=5000 -O3    0.07  21.90

Conclusion结论

Performance-wise性能方面

If you do not need the previous value, make it a habit to use pre-increment.如果不需要之前的值,请养成使用预增量的习惯。 Be consistent even with builtin types, you'll get used to it and do not run risk of suffering unecessary performance loss if you ever replace a builtin type with a custom type.即使与内置类型保持一致,你也会习惯它,并且如果你曾经用自定义类型替换内置类型,就不会冒遭受不必要的性能损失的风险。

Semantic-wise语义明智的

  • i++ says increment i, I am interested in the previous value, though . i++表示increment i, I am interested in the previous value, though
  • ++i says increment i, I am interested in the current value or increment i, no interest in the previous value . ++i表示increment i, I am interested in the current valueincrement i, no interest in the previous value Again, you'll get used to it, even if you are not right now.再一次,你会习惯它,即使你现在不习惯。

Knuth.克努特。

Premature optimization is the root of all evil.过早的优化是万恶之源。 As is premature pessimization.过早的悲观也是如此。

It's not entirely correct to say that the compiler can't optimize away the temporary variable copy in the postfix case.说编译器不能在 postfix 情况下优化掉临时变量副本并不完全正确。 A quick test with VC shows that it, at least, can do that in certain cases.对 VC 的快速测试表明,它至少可以在某些情况下做到这一点。

In the following example, the code generated is identical for prefix and postfix, for instance:在以下示例中,前缀和后缀生成的代码相同,例如:

#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());
}

Whether you do ++testFoo or testFoo++, you'll still get the same resulting code.无论您执行 ++testFoo 还是 testFoo++,您仍然会得到相同的结果代码。 In fact, without reading the count in from the user, the optimizer got the whole thing down to a constant.事实上,没有从用户那里读取计数,优化器就将整个事情归结为一个常数。 So this:所以这:

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

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

Resulted in the following:结果如下:

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

So while it's certainly the case that the postfix version could be slower, it may well be that the optimizer will be good enough to get rid of the temporary copy if you're not using it.因此,虽然后缀版本肯定会变慢,但如果您不使用它,优化器很可能足以摆脱临时副本。

The Google C++ Style Guide says: 谷歌 C++ 风格指南说:

Preincrement and Predecrement预增和预减

Use prefix form (++i) of the increment and decrement operators with iterators and other template objects.将递增和递减运算符的前缀形式 (++i) 与迭代器和其他模板对象一起使用。

Definition: When a variable is incremented (++i or i++) or decremented (--i or i--) and the value of the expression is not used, one must decide whether to preincrement (decrement) or postincrement (decrement).定义:当变量自增(++i 或 i++)或自减(--i 或 i--)且不使用表达式的值时,必须决定是预增(减量)还是后增(减量)。

Pros: When the return value is ignored, the "pre" form (++i) is never less efficient than the "post" form (i++), and is often more efficient.优点:当返回值被忽略时,“pre”形式(++i)永远不会比“post”形式(i++)效率低,而且通常更有效。 This is because post-increment (or decrement) requires a copy of i to be made, which is the value of the expression.这是因为后递增(或递减)需要制作 i 的副本,这是表达式的值。 If i is an iterator or other non-scalar type, copying i could be expensive.如果 i 是迭代器或其他非标量类型,则复制 i 可能会很昂贵。 Since the two types of increment behave the same when the value is ignored, why not just always pre-increment?由于忽略值时两种类型的增量表现相同,为什么不总是预增量?

Cons: The tradition developed, in C, of using post-increment when the expression value is not used, especially in for loops.缺点:在 C 中开发的传统是在不使用表达式值时使用后增量,尤其是在 for 循环中。 Some find post-increment easier to read, since the "subject" (i) precedes the "verb" (++), just like in English.有些人发现后增量更容易阅读,因为“主语”(i)在“动词”(++)之前,就像英语一样。

Decision: For simple scalar (non-object) values there is no reason to prefer one form and we allow either.决定:对于简单的标量(非对象)值,没有理由偏爱一种形式,我们也允许。 For iterators and other template types, use pre-increment.对于迭代器和其他模板类型,使用预增量。

I would like to point out an excellent post by Andrew Koenig on Code Talk very recently.我想指出 Andrew Koenig 最近在 Code Talk 上发表的一篇精彩文章。

http://dobbscodetalk.com/index.php?option=com_myblog&show=Efficiency-versus-intent.html&Itemid=29 http://dobbscodetalk.com/index.php?option=com_myblog&show=Efficiency-versus-intent.html&Itemid=29

At our company also we use convention of ++iter for consistency and performance where applicable.在我们公司,我们还使用 ++iter 的约定来保证适用的一致性和性能。 But Andrew raises over-looked detail regarding intent vs performance.但安德鲁提出了关于意图与性能的被忽视的细节。 There are times when we want to use iter++ instead of ++iter.有时我们想使用 iter++ 而不是 ++iter。

So, first decide your intent and if pre or post does not matter then go with pre as it will have some performance benefit by avoiding creation of extra object and throwing it.因此,首先确定您的意图,如果 pre 或 post 无关紧要,则使用 pre,因为它可以避免创建额外的对象并抛出它,从而带来一些性能优势。

@Ketan @Ketan

...raises over-looked detail regarding intent vs performance. ...提出了有关意图与性能的被忽视的细节。 There are times when we want to use iter++ instead of ++iter.有时我们想使用 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.显然 post 和 pre-increment 有不同的语义,我相信每个人都同意在使用结果时应该使用适当的运算符。 I think the question is what should one do when the result is discarded (as in for loops).我认为问题是当结果被丢弃时应该怎么做(如for循环)。 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.对我自己来说, ++i更自然,但我的经验告诉我,我是少数,使用i++会为大多数阅读你的代码的人带来更少的金属开销。

After all that's the reason the language is not called " ++C ".[*]毕竟这就是语言不被称为“ ++C ”的原因。[*]

[*] Insert obligatory discussion about ++C being a more logical name. [*] 插入关于++C是一个更合乎逻辑的名称的强制性讨论。

  1. ++i - faster not using the return value ++i -不使用返回值更快
  2. i++ - faster using the return value i++ -使用返回值更快

When not using the return value the compiler is guaranteed not to use a temporary in the case of ++i .不使用返回值时,编译器保证不会在++i的情况下使用临时值。 Not guaranteed to be faster, but guaranteed not to be slower.不保证更快,但保证不会更慢。

When using the return value i++ allows the processor to push both the increment and the left side into the pipeline since they don't depend on each other.使用返回值i++允许处理器将增量和左侧都推送到管道中,因为它们不相互依赖。 ++i may stall the pipeline because the processor cannot start the left side until the pre-increment operation has meandered all the way through. ++i 可能会停止流水线,因为处理器无法启动左侧,直到预增量操作一直蜿蜒通过。 Again, a pipeline stall is not guaranteed, since the processor may find other useful things to stick in.同样,不能保证流水线停顿,因为处理器可能会发现其他有用的东西要坚持。

The performance difference between ++i and i++ will be more apparent when you think of operators as value-returning functions and how they are implemented.当您将运算符视为返回值的函数及其实现方式时, ++ii++之间的性能差异将更加明显。 To make it easier to understand what's happening, the following code examples will use int as if it were a struct .为了更容易理解发生了什么,下面的代码示例将使用int ,就好像它是一个struct

++i increments the variable, then returns the result. ++i增加变量,然后返回结果。 This can be done in-place and with minimal CPU time, requiring only one line of code in many cases:这可以就地完成,并且占用最少的 CPU 时间,在许多情况下只需要一行代码:

int& int::operator++() { 
     return *this += 1;
}

But the same cannot be said of i++ .但是i++就不能这样说了。

Post-incrementing, i++ , is often seen as returning the original value before incrementing.后递增, i++ ,通常被视为递增之前返回原始值。 However, a function can only return a result when it is finished .但是,函数只能在完成时返回结果 As a result, it becomes necessary to create a copy of the variable containing the original value, increment the variable, then return the copy holding the original value:因此,有必要创建包含原始值的变量的副本,增加变量,然后返回保存原始值的副本:

int int::operator++(int& _Val) {
    int _Original = _Val;
    _Val += 1;
    return _Original;
}

When there is no functional difference between pre-increment and post-increment, the compiler can perform optimization such that there is no performance difference between the two.当前增量和后增量之间没有功能差异时,编译器可以进行优化,使得两者之间没有性能差异。 However, if a composite data type such as a struct or class is involved, the copy constructor will be called on post-increment, and it will not be possible to perform this optimization if a deep copy is needed.但是,如果涉及structclass等复合数据类型,则在后增时将调用复制构造函数,如果需要深度复制,则无法执行此优化。 As such, pre-increment generally is faster and requires less memory than post-increment.因此,预增量通常比后增量更快并且需要更少的内存。

Mark: Just wanted to point out that operator++'s are good candidates to be inlined, and if the compiler elects to do so, the redundant copy will be eliminated in most cases.马克:只是想指出 operator++ 是内联的好候选者,如果编译器选择这样做,在大多数情况下冗余副本将被消除。 (eg POD types, which iterators usually are.) (例如,迭代器通常是 POD 类型。)

That said, it's still better style to use ++iter in most cases.也就是说,在大多数情况下使用 ++iter 仍然是更好的风格。 :-) :-)

@Mark: I deleted my previous answer because it was a bit flip, and deserved a downvote for that alone. @Mark:我删除了我之前的答案,因为它有点翻转,仅凭这一点就值得投反对票。 I actually think it's a good question in the sense that it asks what's on the minds of a lot of people.我实际上认为这是一个很好的问题,因为它询问了很多人的想法。

The usual answer is that ++i is faster than i++, and no doubt it is, but the bigger question is "when should you care?"通常的答案是 ++i 比 i++ 快,毫无疑问是这样,但更大的问题是“你什么时候应该关心?”

If the fraction of CPU time spent in incrementing iterators is less than 10%, then you may not care.如果用于递增迭代器的 CPU 时间比例小于 10%,那么您可能不在乎。

If the fraction of CPU time spent in incrementing iterators is greater than 10%, you can look at which statements are doing that iterating.如果用于递增迭代器的 CPU 时间比例大于 10%,您可以查看哪些语句正在执行该迭代。 See if you could just increment integers rather than using iterators.看看你是否可以只增加整数而不是使用迭代器。 Chances are you could, and while it may be in some sense less desirable, chances are pretty good you will save essentially all the time spent in those iterators.很有可能你可以,虽然在某种意义上它可能不太理想,但很有可能你基本上可以节省在这些迭代器上花费的所有时间。

I've seen an example where the iterator-incrementing was consuming well over 90% of the time.我见过一个例子,其中迭代器递增消耗了超过 90% 的时间。 In that case, going to integer-incrementing reduced execution time by essentially that amount.在这种情况下,使用整数递增将执行时间基本上减少了那个数量。 (ie better than 10x speedup) (即优于 10 倍加速)

@wilhelmtell @威廉特尔

The compiler can elide the temporary.编译器可以省略临时的。 Verbatim from the other thread:来自另一个线程的逐字逐字:

The C++ compiler is allowed to eliminate stack based temporaries even if doing so changes program behavior.允许 C++ 编译器消除基于堆栈的临时变量,即使这样做会改变程序行为。 MSDN link for VC 8: VC 8 的 MSDN 链接:

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

即使在没有性能优势的内置类型上也应该使用 ++i 的一个原因是为自己创造一个好习惯。

The intended question was about when the result is unused (that's clear from the question for C).预期的问题是关于何时未使用结果(从 C 的问题中可以清楚地看出)。 Can somebody fix this since the question is "community wiki"?由于问题是“社区维基”,有人可以解决这个问题吗?

About premature optimizations, Knuth is often quoted.关于过早优化,Knuth 经常被引用。 That's right.这是正确的。 but Donald Knuth would never defend with that the horrible code which you can see in these days.但唐纳德·克努斯 (Donald Knuth) 永远不会用你在这些日子里看到的可怕代码来辩护。 Ever seen a = b + c among Java Integers (not int)?曾经在 Java 整数(不是 int)中见过 a = b + c 吗? That amounts to 3 boxing/unboxing conversions.这相当于 3 次装箱/拆箱转换。 Avoiding stuff like that is important.避免这样的事情很重要。 And uselessly writing i++ instead of ++i is the same mistake.无用地写 i++ 而不是 ++i 是同样的错误。 EDIT: As phresnel nicely puts it in a comment, this can be summed up as "premature optimization is evil, as is premature pessimization".编辑:正如 phresnel 在评论中很好地指出的那样,这可以概括为“过早的优化是邪恶的,过早的悲观也是邪恶的”。

Even the fact that people are more used to i++ is an unfortunate C legacy, caused by a conceptual mistake by K&R (if you follow the intent argument, that's a logical conclusion; and defending K&R because they're K&R is meaningless, they're great, but they aren't great as language designers; countless mistakes in the C design exist, ranging from gets() to strcpy(), to the strncpy() API (it should have had the strlcpy() API since day 1)).甚至人们更习惯于 i++ 的事实也是不幸的 C 遗产,由 K&R 的概念错误引起(如果您遵循意图论证,那是合乎逻辑的结论;并且因为 K&R 是 K&R 而捍卫 K&R 毫无意义,他们是很棒,但他们作为语言设计者并不出色;C 设计中存在无数错误,从gets() 到strcpy(),再到strncpy() API(从第一天起就应该有strlcpy() API) )。

Btw, I'm one of those not used enough to C++ to find ++i annoying to read.顺便说一句,我是那些对 C++ 不够熟悉的人之一,觉得 ++i 读起来很烦人。 Still, I use that since I acknowledge that it's right.尽管如此,我仍然使用它,因为我承认它是正确的。

Both are as fast ;) If you want it is the same calculation for the processor, it's just the order in which it is done that differ.两者都一样快;) 如果您希望对处理器进行相同的计算,则只是执行顺序不同。

For example, the following code :例如,以下代码:

#include <stdio.h>

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

Produce the following assembly :生产以下组件:

 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

You see that for a++ and b++ it's an incl mnemonic, so it's the same operation ;)你看到 a++ 和 b++ 是一个 incl 助记符,所以它是相同的操作 ;)

++i is faster than i = i +1 because in i = i + 1 two operation are taking place, first increment and second assigning it to a variable. ++ii = i +1快,因为在i = i + 1两个操作,第一次递增,第二次将其分配给变量。 But in i++ only increment operation is taking place.但是在i++只发生增量操作。

Time to provide folks with gems of wisdom ;) - there is simple trick to make C++ postfix increment behave pretty much the same as prefix increment (Invented this for myself, but the saw it as well in other people code, so I'm not alone).是时候为人们提供智慧的宝石了 ;) - 有一个简单的技巧可以使 C++ 后缀增量的行为与前缀增量几乎相同(这是为我自己发明的,但在其他人的代码中也看到了它,所以我不是独自的)。

Basically, trick is to use helper class to postpone increment after the return, and RAII comes to rescue基本上,技巧是使用辅助类在返回后推迟增量,而 RAII 来救援

#include <iostream>

class Data {
    private: class DataIncrementer {
        private: Data& _dref;

        public: DataIncrementer(Data& d) : _dref(d) {}

        public: ~DataIncrementer() {
            ++_dref;
        }
    };

    private: int _data;

    public: Data() : _data{0} {}

    public: Data(int d) : _data{d} {}

    public: Data(const Data& d) : _data{ d._data } {}

    public: Data& operator=(const Data& d) {
        _data = d._data;
        return *this;
    }

    public: ~Data() {}

    public: Data& operator++() { // prefix
        ++_data;
        return *this;
    }

    public: Data operator++(int) { // postfix
        DataIncrementer t(*this);
        return *this;
    }

    public: operator int() {
        return _data;
    }
};

int
main() {
    Data d(1);

    std::cout <<   d << '\n';
    std::cout << ++d << '\n';
    std::cout <<   d++ << '\n';
    std::cout << d << '\n';

    return 0;
}

Invented is for some heavy custom iterators code, and it cuts down run-time. Invented 用于一些繁重的自定义迭代器代码,它减少了运行时间。 Cost of prefix vs postfix is one reference now, and if this is custom operator doing heavy moving around, prefix and postfix yielded the same run-time for me.前缀与后缀的成本现在是一个参考,如果这是自定义运算符进行大量移动,则前缀和后缀为我产生相同的运行时间。

++i is faster than i++ because it doesn't return an old copy of the value. ++ii++快,因为它不返回值的旧副本。

It's also more intuitive:它也更直观:

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

This C example prints "02" instead of the "12" you might expect:这个 C 示例打印“02”而不是您可能期望的“12”:

#include <stdio.h>

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

Same for C++ :与 C++ 相同

#include <iostream>
using namespace std;

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM