4

In K&R Ch 1:

The statement ++nc presents a new operator, ++, which means increment by one. You could instead write nc = nc + 1, but ++nc is more concise and often more efficient.

When would pre-increment be more efficient than the alternative? For most things, at least, the assembly for both is the add (edit: or inc) instruction. When do they differ?

GSerg
  • 76,472
  • 17
  • 159
  • 346
mwlow
  • 141
  • 10
  • I know this is tagged C, and correct me if I'm wrong, but as a curiosity, I believe post increment may be slower than pre increment in C++, even on a modern compiler. Because the C++ standard enforces post increment to call the copy constructor of the object. Reference, [the C++ FAQ](http://www.parashift.com/c++-faq-lite/operator-overloading.html#faq-13.15). – Lundin Dec 23 '11 at 10:07

5 Answers5

10

That text is long out dated. It might have been true in the 70's that compilers would produce more efficient output for ++n, but not any more. All modern compilers will produce identical code.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
3

For most things, at least, the assembly for both is the add instruction.

That's not quite true: there is often a separate "increment by one" instruction. However, that's irrelevant since any half-decent compiler will produce identical machine code for ++nc and nc = nc + 1.

In other words, there is no performance difference. There may have been when the book was written and compilers were not very good, but there isn't anymore.

Community
  • 1
  • 1
NPE
  • 486,780
  • 108
  • 951
  • 1,012
2

I don't know for sure, I'm just thinking out aloud (maybe I shouldn't): Perhaps in K&R's time, ++nc was compiled into something more efficient than nc = nc + 1 (e.g., an increment instruction, rather than an addition). Nowadays, however, compilers probably optimise this automagically.

Xophmeister
  • 8,884
  • 4
  • 44
  • 87
  • I believe `++` was added to early C precisely _because_ no one had written compilers complex enough to use the increment instructions automatically. – Chris Lutz Dec 23 '11 at 09:05
  • There were good enough compilers available at the time, just not on the 24 kB machine that K&R had when writing the first C compiler. It was a *mini-computer* fitting in a single room. :-) http://cm.bell-labs.com/cm/cs/who/dmr/ken-and-den.jpg – Bo Persson Dec 23 '11 at 11:56
1

This is what I could see with gcc -S <filename>. I'll let you derive what you want!

>
> cat 1.c
    #include <stdio.h>

    int main()
    {
        int i=0;
        ++i;

        return 0;
    }

>
> cat 2.c
#include <stdio.h>

int main()
{
    int i=0;
    i++;

    return 0;
}

>
> cat 3.c
#include <stdio.h>

int main(void)
{
    int i=0;
    i = i + 1;

    return 0;
}
>
> gcc -S 1.c 2.c 3.c
>
>
> diff 1.s 2.s
1c1
<       .file   "1.c"
---
>       .file   "2.c"
>
> diff 2.s 3.s
1c1
<       .file   "2.c"
---
>       .file   "3.c"
>
> diff 3.s 1.s
1c1
<       .file   "3.c"
---
>       .file   "1.c"
>
>

The below is the content of the .s file for 1.c and the instructions are identical when compared with 2.s and 3.s!

> cat 1.s
        .file   "1.c"
        .text
.globl main
        .type   main, @function
main:
.LFB2:
        pushq   %rbp
.LCFI0:
        movq    %rsp, %rbp
.LCFI1:
        movl    $0, -4(%rbp)
        addl    $1, -4(%rbp)
        movl    $0, %eax
        leave
        ret
.LFE2:
        .size   main, .-main
        .section        .eh_frame,"a",@progbits
.Lframe1:
        .long   .LECIE1-.LSCIE1
.LSCIE1:
        .long   0x0
        .byte   0x1
        .string "zR"
        .uleb128 0x1
        .sleb128 -8
        .byte   0x10
        .uleb128 0x1
        .byte   0x3
        .byte   0xc
        .uleb128 0x7
        .uleb128 0x8
        .byte   0x90
        .uleb128 0x1
        .align 8
.LECIE1:
.LSFDE1:
        .long   .LEFDE1-.LASFDE1
.LASFDE1:
        .long   .LASFDE1-.Lframe1
        .long   .LFB2
        .long   .LFE2-.LFB2
        .uleb128 0x0
        .byte   0x4
        .long   .LCFI0-.LFB2
        .byte   0xe
        .uleb128 0x10
        .byte   0x86
        .uleb128 0x2
        .byte   0x4
        .long   .LCFI1-.LCFI0
        .byte   0xd
        .uleb128 0x6
        .align 8
.LEFDE1:
        .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-48)"
        .section        .note.GNU-stack,"",@progbits
>
Sangeeth Saravanaraj
  • 16,027
  • 21
  • 69
  • 98
1

For "normal" variables there should be no difference as other answers suggest. Only if nc is voloatile qualified the result could be different. For such a variable the +1 form must first evaluate the expression nc that is load nc and then perform the addition. For the ++ form the compiler still could take shortcuts and increment the variable in place.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177