Instructions
x86-64INC / DEC
Increment and decrement by one. Smaller than ADD/SUB and almost identical — except they deliberately leave the carry flag (CF) untouched.
INC dst adds 1, DEC dst subtracts 1. They take a single register or memory
operand and are a byte or two shorter than the equivalent add dst, 1 /
sub dst, 1.
inc eax ; eax += 1
dec rcx ; rcx -= 1
inc DWORD PTR [rbx] ; ++(*p)The CF gotcha
INC and DEC update the usual arithmetic flags (OF, SF, ZF, AF, PF)
but deliberately preserve CF. ADD/SUB update CF as well. This is the
one behavioural difference that matters:
- It lets you increment a loop counter inside a multi-precision add/subtract
loop without clobbering the carry you're propagating with
ADC/SBB. - It means
inc/decare not safe substitutes foradd 1/sub 1if the following code branches onCF(e.g.jc/jae).
Reverse-engineering notes
- A
dec/incimmediately followed by a signed or zero branch (jz,jnz,js,jle, …) is the classic countdown/count-up loop — those conditions readZF/SF, whichdec/incdo set. - On modern Intel/AMD,
inc/deccan incur a partial-flags stall because they do a read-modify-write of the flags register. For that reason compilers in-O2/-O3often emitadd reg, 1/sub reg, 1instead, even though it's one byte larger. Hand-written and size-optimised (-Os) code favoursinc/dec. - In 32-bit x86 the single-byte forms
0x40+r/0x48+rwere the shortest way to bump a register. In 64-bit mode those encodings were repurposed as the REX prefix, soinc/decnow require a ModR/M byte — they lost their size edge, reinforcing the compiler's preference foradd/sub.
Try it — Virtual CPU
open full playground →- 1 mov eax, 5
- 2 inc eax
- 3 inc eax
- 4 dec eax
- 5
step 0
▸ Loading emulator…