我们以下面这么一段代码开始

void test_inc() {
   int i = 10;
   i = i++;
   printf("i = %d\n", i);
}

运行输出

i = 10

看起来出乎意料,来我们看看他编译之后的汇编代码就明白了

test_inc:
.LFB20:
        .cfi_startproc
        endbr64
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movl    $10, -4(%rbp)
        movl    -4(%rbp), %eax
        leal    1(%rax), %edx
        movl    %edx, -4(%rbp)
        movl    %eax, -4(%rbp)
        movl    -4(%rbp), %eax
        movl    %eax, %esi
        leaq    .LC11(%rip), %rdi
        movl    $0, %eax
        call    printf@PLT
        nop
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc

可以看出i++的流程是这样的

R1 = i;

R2 = R1 + 1;

i = R2;

i = R1;

这就可以解释i的值最终没有变化。

所以编译器编译后产生的指令流程是先把+1后的值写回i,然后又把+1之前暂存在寄存器里的i的值赋值给i。i的值先变成11,然后又变回10了。