33

In C language, Why does n++ execute faster than n=n+1?

(int n=...;  n++;)
(int n=...;  n=n+1;)

Our instructor asked that question in today's class. (this is not homework)

  • 9
    How did you find that out? On which compiler/OS/platform/architecture? – Mehrdad Afshari May 21 '10 at 18:59
  • 77
    It doesn't, in general. You can't make a meaningful statement that "`a` is faster than `b`" (where `a` and `b` are C expressions). It only makes sense to say that "`a` is faster than `b` on hardware `c` when compiled with version `d` of compiler `e` with optimization flags `f`" (and a few other requirements, as well). – Stephen Canon May 21 '10 at 19:04
  • 11
    It's clear what's being asked here from the example; just because the answer seems obvious doesn't mean you should close it. +1 for reopen. – bdonlan May 21 '10 at 19:15
  • 1
    Yes, I think it must be reopened.. – Betamoo May 21 '10 at 19:17
  • 4
    @bdonlan: It's not a real question because it asks why a meaningless statement is true. It might as well ask "Why do green ideas sleep furiously?". – Stephen Canon May 21 '10 at 19:19
  • 2
    @Stephen Canon: At least it was true sometime in the far past.. – Betamoo May 21 '10 at 19:21
  • 14
    @Stephen: So the questioner should be corrected in the answer. It's still a good question, because someone else might come across the same misinformation later, and this question will help sort them out – bdonlan May 21 '10 at 19:22
  • 5
    @Stephen, also, if you truly feel that the question shouldn't ask a false statement, feel free to edit it to "Is `n++` faster than `n = n + 1`, and why?". That's far more constructive than simply closing it without discussion :) – bdonlan May 21 '10 at 19:23
  • 1
    possible duplicate of [(C) What is the difference between ++i and i++](http://stackoverflow.com/questions/24853/c-what-is-the-difference-between-i-and-i) – Tim Post May 21 '10 at 19:53
  • 2
    Unless you provide some kind of context, please stop rolling back edits that link to questions that are _clearly_ related to what you are asking. – Tim Post May 21 '10 at 20:09
  • 1
    And for that matter, please stop reverting attempts to make this a clearer and more instructive question; at least add a comment if you disagree with the edits. – ZoogieZork May 21 '10 at 20:15
  • I do not think this should be in community wiki.. – Betamoo May 21 '10 at 20:20
  • 1
    @Betamoo: Too late. SO automatically converts a question to Community Wiki if 5 or more people edit a question. – Powerlord May 21 '10 at 20:28
  • 1
    Vote to reopen. I don't see how this is not a real question. Just because the OP has a bad teacher doesn't mean the question isn't legitimate. – Ben Zotto May 21 '10 at 21:09
  • @gcc: `n++;` and `n=n+1;` will almost certainly compile to the same exact machine code on any modern compiler. On the first C compilers this was not the case and the compiler would only realize that it could use the target processor's increment instruction if you told it `n++`. Otherwise it would do the more general add instruction which would have either been a bigger instruction or have been two instructions. If your instructor really told you that it was faster and was not talking about it being faster for you to type "n++" than "n=n+1" then he is wrong. Try `gcc -S prog.c;less prog.s` – nategoose May 21 '10 at 22:16
  • 4
    @quixoto: It was closed, then fixed up into a real question and reopened, then the OP reverted and the question was closed again. Frankly, if the OP is going to be pulling that kind of behavior, then IMHO it should stay closed. – ZoogieZork May 21 '10 at 22:22
  • 3
    I believe this is not a real question, since it postulates a false situation, and has no answer. "Why are zebras larger than elephants?" – David Thornley May 28 '10 at 19:06
  • 2
    WTF why did somebody put a bounty on a community wiki question with an accepted answer and blatantly false premises?! – R.. GitHub STOP HELPING ICE Dec 17 '10 at 17:52
  • 1
    The real question is: Why is your university allowing such an incompetent professor to teach? – R.. GitHub STOP HELPING ICE Dec 17 '10 at 20:11
  • To answer my own question: having a bounty makes a question unclosable. So apparently gcc put the bounty on it to keep us from closing it. – R.. GitHub STOP HELPING ICE Dec 18 '10 at 01:39
  • Hey, I'll agree that ++n is more optimized than n++. But n=n+1? LOL! – Nav Dec 20 '10 at 13:14
  • @Nav: Either you're joking or you missed that this question is tagged C and not C++.... – R.. GitHub STOP HELPING ICE Dec 20 '10 at 16:26
  • 1
    I don't know about execution, but the compile may take a jokingly small amount of less time, since `n=n+1;` would take 2 bytes longer than `n++;` to get into the memory. Again this assumption might be true only for some pre-stone age era, as we now have block reads and writes and the stuff... – Halil Özgür Dec 23 '10 at 16:30
  • 3
    This same question is on the NASCAR blog as "My brother's friend's uncle says his car is faster if it is number 01 then 10". – RC_Cleland Dec 24 '10 at 02:01
  • @RC_Cleland: Wow can I give 5 +1's? You almost made me spit out my coffee laughing. – R.. GitHub STOP HELPING ICE Dec 24 '10 at 13:49
  • possible duplicate of [is there any difference in terms of efficiency of using i++/++i/i+=1/i=i+1 when none compiler optimization is used](http://stackoverflow.com/questions/4523618/is-there-any-difference-in-terms-of-efficiency-of-using-i-i-i-1-i-i1-when-n) – R.. GitHub STOP HELPING ICE Dec 24 '10 at 22:26

10 Answers10

103

That would be true if you are working on a "stone-age" compiler...

In case of "stone-age":
++n is faster than n++ is faster than n=n+1
Machine usually have increment x as well as add const to x

  • In case of n++, you will have 2 memory access only (read n, inc n, write n )
  • In case of n=n+1, you will have 3 memory access (read n, read const, add n and const, write n)

But today's compiler will automatically convert n=n+1 to ++n, and it will do more than you may imagine!!

Also on today's out-of-order processors -despite the case of "stone-age" compiler- runtime may not be affected at all in many cases!!

Related

Community
  • 1
  • 1
Betamoo
  • 14,964
  • 25
  • 75
  • 109
  • *Why* would it be try on a "stone-age" compiler? – FrustratedWithFormsDesigner May 21 '10 at 19:02
  • Because it's not smart enough to automatically convert `n=n+1` to `n++`; it would do the whole load, operate, store business as if `1` were any other constant value. – Carl Manaster May 21 '10 at 19:06
  • No, it is not always machine instruction difference, but it is always memory access one! – Betamoo May 21 '10 at 19:14
  • 6
    @gcc: No, you should NOT say that. You should say "There should be no difference at all between the two. Optimizing compilers have handled things like this for decades, since at least the Bliss-11 compiler described in "Design of an Optimizing Compiler", by Wulf et al." – John R. Strohm May 21 '10 at 19:14
  • 4
    On the computer I learned about this on, `++n` and `n++` were exactly the same speed, it didn't have to do load-increment-store, and the only speed difference you'd see depended on whether `n` was stored in a register or memory (not whether n happened to be in a register right now, but whether or not its allocated storage was in a register) e.g. `move (n)+,r0` moves n to register zero, incrementing n after the move. (VAX-11 assembly) – Stephen P May 21 '10 at 19:33
  • 2
    +1 for actually answering the question in a useful way as opposed to just saying that they're the same, which is useful to know but not the information the OP probably wanted. – Ben Zotto May 21 '10 at 20:11
  • 3
    Saying the compiler will "convert `n=n+1` to `++n`" is simply wrong, or even nonsense. It's like saying a translator will "convert `it is` to `it's`" when translating English to French. The distinction between the two is an artifact of the *source language*. – R.. GitHub STOP HELPING ICE Dec 17 '10 at 20:14
  • 2
    I was taught. ++n may be faster, but is never slower than n++. For any given hardware. – EnabrenTane Dec 23 '10 at 05:41
  • @Steve - could you please elaborate this "`++n` may be faster than `n++` because it doesn't require the previous value of n to be copied, saved during the increment, and returned."? – Sandeepan Nath Dec 23 '10 at 19:40
  • 2
    It's a standard C++ classroom mantra that's been carried over to C and become nonsense in the process. Note that in C there's no such thing as applying either `++` operator to "a large and expensive-to-copy datatype". But even if there were, no copying is involved. The increment happens *any time after the postincrement operator but before the next time the value is used*, long after the value was used in the current expression. – R.. GitHub STOP HELPING ICE Dec 24 '10 at 00:07
  • @Steve, please note that R said in _C_ not in _C++_ because this question is about _C_ not _C++_. in C there is no such thing as overloading. `++` can _only_ be applied to numeric types in C thus there is never any need to copy anything. – tobyodavies Dec 24 '10 at 08:05
  • @tobyodavies - whoops - you're right - nonsense comments deleted –  Dec 24 '10 at 09:17
  • @Betamoo, What about if the constant is 0 instead of 1? if its `n=n+0` instead of `n=n+1`? – Pacerier Aug 12 '17 at 09:34
  • @Pacerier A 'stone-age' compiler would do (read n; read const; write n), whereas any proper compiler will immediately see that this is a no-op, and will not add anything to the assembly. – Qqwy Nov 29 '18 at 12:11
  • @Qqwy: It would only be a no-op if `n` isn't volatile, of course. If `n` is volatile, a compiler could document that `n++;` and `n=n+1;` will be performed using different instructions which might sometimes have different corner-case semantics on the target platform. – supercat Nov 09 '21 at 07:33
42

On GCC 4.4.3 for x86, with or without optimizations, they compile to the exact same assembly code, and thus take the same amount of time to execute. As you can see in the assembly, GCC simply converts n++ into n=n+1, then optimizes it into the one-instruction add (in the -O2).

Your instructor's suggestion that n++ is faster only applies to very old, non-optimizing compilers, which were not smart enough to select the in-place update instructions for n = n + 1. These compilers have been obsolete in the PC world for years, but may still be found for weird proprietary embedded platforms.

C code:

int n;

void nplusplus() {
    n++;
}

void nplusone() {
    n = n + 1;
}

Output assembly (no optimizations):

    .file   "test.c"
    .comm   n,4,4
    .text
.globl nplusplus
    .type   nplusplus, @function
nplusplus:
    pushl   %ebp
    movl    %esp, %ebp
    movl    n, %eax
    addl    $1, %eax
    movl    %eax, n
    popl    %ebp
    ret
    .size   nplusplus, .-nplusplus
.globl nplusone
    .type   nplusone, @function
nplusone:
    pushl   %ebp
    movl    %esp, %ebp
    movl    n, %eax
    addl    $1, %eax
    movl    %eax, n
    popl    %ebp
    ret
    .size   nplusone, .-nplusone
    .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
    .section    .note.GNU-stack,"",@progbits

Output assembly (with -O2 optimizations):

    .file   "test.c"
    .text
    .p2align 4,,15
.globl nplusplus
    .type   nplusplus, @function
nplusplus:
    pushl   %ebp
    movl    %esp, %ebp
    addl    $1, n
    popl    %ebp
    ret
    .size   nplusplus, .-nplusplus
    .p2align 4,,15
.globl nplusone
    .type   nplusone, @function
nplusone:
    pushl   %ebp
    movl    %esp, %ebp
    addl    $1, n
    popl    %ebp
    ret
    .size   nplusone, .-nplusone
    .comm   n,4,4
    .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
    .section    .note.GNU-stack,"",@progbits
bdonlan
  • 224,562
  • 31
  • 268
  • 324
13

The compiler will optimize n + 1 into nothingness.

Do you mean n = n + 1?

If so, they will compile to identical assembly. (Assuming that optimizations are on and that they're statements, not expressions)

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
5

Who says it does? Your compiler optimizes it all away, really, making it a moot point.

3

Modern compilers should be able to recognize both forms as equivalent and convert them to the format that works best on your target platform. There is one exception to this rule: variable accesses that have side effects. For example, if n is some memory-mapped hardware register, reading from it and writing to it may do more than just transferring a data value (reading might clear an interrupt, for instance). You would use the volatile keyword to let the compiler know that it needs to be careful about optimizing accesses to n, and in that case the compiler might generate different code from n++ (increment operation) and n = n + 1 (read, add, and store operations). However for normal variables, the compiler should optimize both forms to the same thing.

bta
  • 43,959
  • 6
  • 69
  • 99
  • This answer is wrong. `volatile` does not result in any difference between `++n` and `n=n+1`. Both result in a single read and a single write, and neither is atomic. If you want atomicity, `volatile` cannot provide it; wait for `_Atomic` types in C1x. – R.. GitHub STOP HELPING ICE Dec 20 '10 at 17:19
  • 2
    @R: I never claimed that 'volatile' provided atomicity. The rest of your comment is not true in the general case (save the last sentence); the details of how a compiler optimizes code is implementation-specific. My answer merely explains how using 'volatile' may affect compiler optimization in general. – bta Dec 21 '10 at 02:01
  • @R..GitHubSTOPHELPINGICE: The Standard does not require that `volatile` provide atomicity, but if a platform is capable of performing a few atomic operations on hardware registers without supporting all of the ones mandated to claim support for C11 atomics, documenting that it implements a few constructs involving `volatile` in atomic fashion would seem the most practical way of providing such support. Far better than atomic types that must implement all operations in broken fashion and can't implement any in the useful fashion supported by hardware. – supercat Nov 09 '21 at 07:36
2

It doesn't really. The compiler will make changes specific to the target architecture. Micro-optimizations like this often have dubious benefits, but importantly, are certainly not worth the programmer's time.

Puppy
  • 144,682
  • 38
  • 256
  • 465
2

Actually, the reason is that the operator is defined differently for post-fix than it is for pre-fix. ++n will increment "n" and return a reference to "n" while n++ will increment "n" will returning a const copy of "n". Hence, the phrase n = n + 1 will be more efficient. But I have to agree with the above posters. Good compilers should optimize away an unused return object.

wheaties
  • 35,646
  • 15
  • 94
  • 131
  • 1
    @R and more to the point looking at the history it was edited an astounding 13 times complete with title change, tag changes, and question changes. To mark me down while not taking the historical context is quite poor. Normally I wouldn't be so uppity but does this mean I need to go through all my answers to make sure that the question hasn't been edited to the point where I could get downvoted several months later? – wheaties Sep 20 '10 at 04:06
  • Sorry, I wasn't aware. I'd remove the -1 if I could. – R.. GitHub STOP HELPING ICE Dec 17 '10 at 20:16
  • @R Why can't you remove the -1? – Ergwun Dec 22 '10 at 00:49
  • After it's been there a certain length of time, you can only change your vote if the answer is edited. – R.. GitHub STOP HELPING ICE Dec 23 '10 at 23:55
2

In C language the side-effect of n++ expressions is by definition equivalent to the side effect of n = n + 1 expression. Since your code relies on the side-effects only, it is immediately obvious that the correct answer is that these expression always have exactly equivalent performance. (Regardless of any optimization settings in the compiler, BTW, since the issue has absolutely nothing to do with any optimizations.)

Any practical divergence in performance of these expressions is only possible if the compiler is intentionally (and maliciously!) trying to introduce that divergence. But in this case it can go either way, of course, i.e. whichever way the compiler's author wanted to skew it.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • 1
    -1: old compilers used to emit different instructions for the different statements because they weren't advanced enough at optimization... – RCIX May 24 '10 at 02:33
  • 1
    @RCIX: What you are saying is absolute nonsense, based on a ridiculous urban legend, according to which the compilers somehow translate C code into machine code in some *literal* fashion. In reality, if the defined semantics of two expressions is the same, the code will be the same. It has absolutely nothing to do with optimization. If your compiler produced different code in this case, it simply meant that your compiler was broken, not that it wasn't "advanced enough at optimization". – AnT stands with Russia May 24 '10 at 04:34
  • 4
    No, many simple compilers really do a literal translation, such as always using an ADD instruction for the "+" operator, even in cases where INC would be better. For instance, it used to be common to manually use ">>" to divide by a power of two, because the compiler would use a very slow DIV instruction if you used the "/" operator. – Daniel Newby May 28 '10 at 00:38
  • 2
    @Daniel Newby: That would mean a naive non-production grade compiler. I.e. a compiler written by people who did not understand what they were doing. People, who implemented their own misconceptions about C language instead of the actual specification of C language. Why would someone use such a "compiler" is beyond me. In reality there's no such thing as "literal translation" in C. Nothing in the language specification implies that `+` should be implemented as ADD and that `++` should be implemented by INC. – AnT stands with Russia May 28 '10 at 01:02
  • 3
    @AndreyT: No, it just means a simple compiler, which is still common for microcontrollers and oddball systems. There are entire compiler companies for niche platforms that have fewer employees than the Visual C++ optimization team, and their products are quite useful, although the machine code efficiency leaves something to be desired. Moreover C was intentionally designed so that operators map directly to common machine instructions, so simple direct translation would produce a complete compiler. – Daniel Newby May 29 '10 at 00:07
  • Having fewer employees is no excuse for complete failure to understand the C language. Would you hire somebody who doesn't understand German to translate from German to English? Then why would you hire somebody who doesn't understand C to write a C compiler? – R.. GitHub STOP HELPING ICE Dec 17 '10 at 20:17
  • That something isn't mandated by the standard doesn't mean it isn't normally done and intended to be done that way. One sign of the intended relatively simple translation from source to object code is the amount of stuff that is left undefined by the standard, so that you can just accept whatever the hardware naturally does in that simple mapping. For example, the sign behaviour of `%` isn't specified, so whether your hardware gives you an unsigned modulo or a potentially signed remainder as a machine instruction, you can still map the operator fairly simply to that machine instruction. –  Dec 24 '10 at 09:25
  • @Steve314: There's nothing left "undefined" in this case. In fact, the standard explicitly defines/requires the equivalence between `++` variant and `+ 1` variant, which is the entire point. The reason the standard has so much stuff left undefined is to give compiler more freedom in optimizing the code. Ironically, in most cases (including this one) this is actually the opposite of the primitive translation approach when C operations are just straightforwardly mapped to machine operations. – AnT stands with Russia Dec 24 '10 at 14:50
  • 1
    @AndreyT - the functional equivalence is mandated. Identical implementation (and performance) is not. A different implementation does not mean a different result. Compilers can choose to implement ++ differently to +=1 and, especially historically, have often done so. There is a story I vaguely remember (no guarantee of accuracy) about the original C compiler including prefix and postfix variants of the ++ and -- operators specifically to exploit specialised addressing modes for the target platforms machine code when used for pointers that were also dereferenced, and indexes used with []. –  Dec 29 '10 at 03:12
  • In fact a compiler can implement `x++; y++;` in such a way that one uses `INC`, the other uses `ADD 1`. Hell, it can use `SUB -1` if it really wanted to. The point is, even for literally identical C code, the generated code can differ from instance to instance. Only semantics matter in the end. I would like someone to implement an -O-1 option for GCC one of these days to deoptimize code :D – Thomas Eding Jan 18 '12 at 06:27
2

I think it's more like a hardware question rather than software... If I remember corectly, in older CPUs the n=n+1 requires two locations of memory, where the ++n is simply a microcontroller command... But I doubt this applies for modern architectures...

Loupax
  • 4,728
  • 6
  • 41
  • 68
0

All those things depends on compiler/processor/compilation directives. So make any assumptions "what is faster in general" is not a good idea.

Nickolay Olshevsky
  • 13,706
  • 1
  • 34
  • 48