Why Does ++i + i++ Print 3? Exploring C Evaluation Order with Assembly
This article dissects the C expression ++i + i++, shows how compiler‑generated assembly executes both increments exactly once, and demonstrates why the result is 3 while highlighting the pitfalls of undefined evaluation order in C.
Expression ++i + i++ in C
The increment operators have higher precedence than addition, and both have higher precedence than assignment, so ++i and i++ are evaluated before the + operator.
Compilation and generated assembly (gcc -O0 -S)
# assembly generated for ++i + i++
.file "1125.c"
.text
.globl main
main:
subq $16, %rsp
movl $0, -8(%rbp) # i = 0
addl $1, -8(%rbp) # ++i, i becomes 1
movl -8(%rbp), %eax # load i (1) into %eax
leal 1(%rax), %edx # i++ (post‑increment), %edx = 2
movl %edx, -8(%rbp) # store incremented i (2)
addl %edx, %eax # %eax + %edx = 1 + 2 = 3
movl %eax, -4(%rbp) # store result
...The assembly shows that the original value of i (1) is loaded into %eax, then i is incremented to 2, and finally the two values are added, producing the result 3.
Variant i++ + ++i
# assembly generated for i++ + ++i
movl $0, -8(%rbp) # i = 0
movl -8(%rbp), %eax # load i (0)
leal 1(%rax), %edx # ++i, %edx = 1
movl %edx, -8(%rbp) # store incremented i (1)
addl $1, -8(%rbp) # i++ (post‑increment), i becomes 2
movl -8(%rbp), %edx # load new i (2)
addl %edx, %eax # %eax + %edx = 0 + 1 = 1 (the addition uses the value before the post‑increment)
...Here the post‑increment loads the original i (0) into %eax, the pre‑increment makes i become 1, and the addition yields 1 (0 + 1).
Manual assembly assembly and execution script
# 1125.sh – assemble, link and run the program
# gcc -O0 -S 1125.c (produces 1125.s)
as -o 1125.o 1125.s
ld -m elf_x86_64 -dynamic-linker /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 \
"1125.o" /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o \
/usr/lib/gcc/x86_64-linux-gnu/5/crtbegin.o /usr/lib/gcc/x86_64-linux-gnu/5/crtend.o \
/usr/lib/x86_64-linux-gnu/crtn.o -lc -o "1125_64"
chmod 777 1125_64
./1125_64Modifying the generated assembly to reset -8(%rbp) to zero before the increment sequence still produces the value 3, confirming that each increment is executed exactly once.
Key instruction sequence for ++i + i++
Initialize i at -8(%rbp) to 0. addl $1, -8(%rbp) // ++i, i becomes 1. movl -8(%rbp), %eax // load i (1) into %eax. leal 1(%rax), %edx // i++ (post‑increment), %edx = 2. movl %edx, -8(%rbp) // store incremented i (2). addl %edx, %eax // 1 + 2 = 3.
Key instruction sequence for i++ + ++i
Initialize i to 0. movl -8(%rbp), %eax // load original i (0). leal 1(%rax), %edx // ++i, %edx = 1. movl %edx, -8(%rbp) // store incremented i (1). addl $1, -8(%rbp) // i++ (post‑increment), i becomes 2. addl %edx, %eax // 0 + 1 = 1.
These experiments demonstrate that the order of evaluation of sub‑expressions in C is undefined. Relying on side‑effects such as multiple increments of the same variable within a single expression can lead to surprising results.
Reference: https://zh.cppreference.com/w/c/language/eval_order
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
