▌今天群里的激烈讨论代码
#include "stdio.h"
#include "stdio.h"
int main()
{
int i = 0;
int value = ++i+i++;
printf("%d\n", value);
return 0;
}
我们先从正常的逻辑讨论下这个问题
这里需要考虑下i运算符的优先级
然后,并没有什么用处
++ 的优先级高于 + ++ 和 + 的优先级高于 =
那++i 和 i++ 都被执行了一次1 + 2 = 3
.
▌我写了一个脚本,用来转换并执行汇编代码的
# 1125.sh
#gcc -O0 -S 1125.c
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"
sudo chmod 777 1125_64
./1125_64
在生成的汇编代码中,我们可以修改汇编,然后再执行看结果
.file "1125.c"
.text
.section .rodata
.LC0:
.string "%d\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $0, -8(%rbp)
addl $1, -8(%rbp)
movl -8(%rbp), %eax
leal 1(%rax), %edx
movl %edx, -8(%rbp)
movl -8(%rbp), %edx
addl %edx, %eax
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 9.4.0-1ubuntu1~16.04) 9.4.0"
.section .note.GNU-stack,"",@progbits
▌核心代码其实就下面几句
i
刚开始在-8(%rbp)
这个寄存器中-8(%rbp)
寄存器 自加1再把 -8(%rbp)
传给%eax
寄存器再 %eax
寄存器 自加1再把两个寄存器的值相加得到结果 3
subq $16, %rsp
movl $0, -8(%rbp)
addl $1, -8(%rbp) #add i + 1 = 2
movl -8(%rbp), %eax
leal 1(%rax), %edx
movl %edx, -8(%rbp)
movl -8(%rbp), %edx
addl %edx, %eax #add 1 + 2 = 3
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
movl %eax, %esi
movl $.LC0, %edi
如果我们把这部分修改成这样再执行呢?
movl $0, -8(%rbp)
movl -8(%rbp), %eax
leal 1(%rax), %edx
movl %edx, -8(%rbp)
movl -8(%rbp), %edx
addl %edx, %eax #add 1 + 2 = 3
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
结果是
这样调戏汇编代码还是挺有意思的哦。
▌那如果是这样的C 代码呢?
#include "stdio.h"
int main()
{
int i = 0;
int value = i++ + ++i;
printf("%d\n", value);
return 0;
}
对应的关键汇编代码
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $0, -8(%rbp)
movl -8(%rbp), %eax
leal 1(%rax), %edx
movl %edx, -8(%rbp)
addl $1, -8(%rbp)
movl -8(%rbp), %edx
addl %edx, %eax
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %eax
leave
看汇编的意思是,先把 i 自加成1,然后把两个i 相加。
参考
https://zh.cppreference.com/w/c/language/eval_order
END