Prismjs

What is the difference between ++i and i++ in a for loop?

i++ and ++i are classic topics in C-system languages,
We know that the apparent difference between i++ and +++i is that the return value of +++i is i+1, while i++ is i, and their low-level implementations are:

  • ++i implementation:

``c’’ int operator ++ () { return i+1; }

* i++ implementation:

``c
int operator ++ (int flag)
{
    int j = i;
    i += 1;
    return j;
}

The essential difference between the two implementations is the j, which is called the anonymous variable in the program.
It is now obvious that the existence of this anonymous variable is a direct result of the fact that i++ is more expensive than +++i.
So, does this mean that for(int i = 0;i < n;i++) is more expensive than for(int i = 0;i < n;++i)?
With this in mind, I think it may be necessary to compare assemblies to see the difference.
Now create two separate files with the following contents:
``c’’ #include

int main() { for (int i = 0; i < 100; ++i) { printf(“%d\n”, i); } return 0; }

``c
#include <stdio.h>
 
int main()
{
    for (int i = 0; i < 100; i++)
    {
        printf("%d\n", i);
    }
    return 0;
}

However, unfortunately, the two copies of the C code output exactly the same after using gcc to output the assembly code:
``c’’ .section __TEXT,__text,regular,pure_instructions .macosx_version_min 10, 13 .globl _main ## – Begin function main .p2align 4, 0x90 _main: ## @main .cfi_startproc

BB#0:

pushq %rbp Lcfi0:
.cfi_def_cfa_offset 16 Lcfi1:
.cfi_offset %rbp, -16
movq %rsp, %rbp Lcfi2:
.cfi_def_cfa_register %rbp
subq $16, %rsp
movl $0, -4(%rbp)
movl $0, -8(%rbp) LBB0_1: ## =>This Inner Loop Header: Depth=1
cmpl $100, -8(%rbp)
jge LBB0_4 ## BB#2: ## in Loop: Header=BB0_1 Depth=1
leaq L_.str(%rip), %rdi
movl -8(%rbp), %esi
movb $0, %al
callq _printf
movl %eax, -12(%rbp) ## 4-byte Spill ## BB#3: ## in Loop: Header=BB0_1 Depth=1
movl -8(%rbp), %eax
addl $1, %eax
movl %eax, -8(%rbp)
jmp LBB0_1 LBB0_4:
xorl %eax, %eax
addq $16, %rsp
popq %rbp
retq
.cfi_endproc
                                    ## -- End function
.section __TEXT,__cstring,__cstring_literals L_.str: ## @.str
.asciz "%d\n"

.subsections_via_symbols

So, only two guesses can be made at this point:
* The compiler level has optimized the iterations in the for loop.
* :: Compiler-level optimizations for cases where no ++i/i++ operation is taken.  
On second thought, if we do the compiler optimizations ourselves, we should do the second one, because the first one is a little bit too simple and we will get the features of the first one automatically after doing the second one.  
We continue to prepare 2 more C files:

``c
#include <stdio.h>
 
int main()
{
    int i = 0;
    int = 0; i++;
    return 0;
}

``c #include

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

The two C code output of the assembly is also the same, I will not post the assembly ...  
Let's prepare two more C language files:
``c''
#include <stdio.h>
 
int main()
{
    printf("%d\n", i++); int i = 0;
    printf("%d\n", i++);
    return 0;
}

``c #include

int main() { printf(“%d\n”, ++i); int i = 0; printf(“%d\n”, ++i); return 0; }

Now the answer is revealed, the output of these 2 C files embody the difference between the assemblies.
``c''
	.section __TEXT,__text,regular,pure_instructions
	.macosx_version_min 10, 13
	.globl _main ## -- Begin function main
	.p2align 4, 0x90
_main: ## @main
	.cfi_startproc
## BB#0:
	pushq %rbp
Lcfi0:
	.cfi_def_cfa_offset 16
Lcfi1:
	.cfi_offset %rbp, -16
	movq %rsp, %rbp
Lcfi2:
	.cfi_def_cfa_register %rbp
	subq $16, %rsp
	leaq L_.str(%rip), %rdi
	movl $0, -4(%rbp)
	movl $0, -8(%rbp)
	movl -8(%rbp), %eax
	addl $1, %eax
	movl %eax, -8(%rbp)
	movl %eax, %esi
	movb $0, %al
	callq _printf
	xorl %esi, %esi
	movl %eax, -12(%rbp) ## 4-byte Spill
	movl %esi, %eax
	addq $16, %rsp
	popq %rbp
	retq
	.cfi_endproc
                                        ## -- End function
	.section __TEXT,__cstring,__cstring_literals
L_.str: ## @.str
	.asciz "%d\n"


.subsections_via_symbols

``c .section __TEXT,__text,regular,pure_instructions .macosx_version_min 10, 13 .globl _main ## – Begin function main .p2align 4, 0x90 _main: ## @main .cfi_startproc

BB#0:

pushq %rbp Lcfi0:
.cfi_def_cfa_offset 16 Lcfi1:
.cfi_offset %rbp, -16
movq %rsp, %rbp Lcfi2:
.cfi_def_cfa_register %rbp
subq $16, %rsp
leaq L_.str(%rip), %rdi
movl $0, -4(%rbp)
movl $0, -8(%rbp)
movl -8(%rbp), %eax
movl %eax, %ecx
addl $1, %ecx
movl %ecx, -8(%rbp)
movl %eax, %esi
movb $0, %al
callq _printf
xorl %ecx, %ecx
movl %eax, -12(%rbp) ## 4-byte Spill
movl %ecx, %eax
addq $16, %rsp
popq %rbp
retq
.cfi_endproc
                                    ## -- End function
.section __TEXT,__cstring,__cstring_literals L_.str: ## @.str
.asciz "%d\n"

.subsections_via_symbols


i++ has one more line than +++i
``c
    movl %eax, %ecx

So the final conclusion is that, at least at the gcc compiler level, there is no real difference between i++ and +++i in iterations of for loops.
And, perhaps we can use other compilers to check if other compilers are optimized as well.