Skip to content

Instructions

x86-64

INC / 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.

asm
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/dec are not safe substitutes for add 1/sub 1 if the following code branches on CF (e.g. jc/jae).

Reverse-engineering notes

  • A dec/inc immediately followed by a signed or zero branch (jz, jnz, js, jle, …) is the classic countdown/count-up loop — those conditions read ZF/SF, which dec/inc do set.
  • On modern Intel/AMD, inc/dec can incur a partial-flags stall because they do a read-modify-write of the flags register. For that reason compilers in -O2/-O3 often emit add reg, 1 / sub reg, 1 instead, even though it's one byte larger. Hand-written and size-optimised (-Os) code favours inc/dec.
  • In 32-bit x86 the single-byte forms 0x40+r / 0x48+r were the shortest way to bump a register. In 64-bit mode those encodings were repurposed as the REX prefix, so inc/dec now require a ModR/M byte — they lost their size edge, reinforcing the compiler's preference for add/sub.

See also: ADD / SUB · ADC / SBB · RFLAGS.

Try it — Virtual CPU

open full playground →
  1. 1 mov eax, 5
  2. 2 inc eax
  3. 3 inc eax
  4. 4 dec eax
  5. 5
step 0
Loading emulator…