(++i)+(i++)


c++

一个无聊的老题了。标准答案当然是”It depends.”。但是,模拟计算一下,却会发现这貌似并没有歧义:

(假定初始时i = 0)

  1. 加法,从左到右计算每个子表达式*,因此先计算++i,再计算i++
  2. ++i,i立即自增1,并返回1
  3. i++,先返回i(=1),等到语句结束时i自增1
  4. 计算加法,结果等于2;语句结束时i自增1,等于2

* 若从右至左计算每个子表达式,则结果为1;结束时i=2

测试代码:

1
2
3
4
5
6
7
8
9
#include <stdio.h>

int main()
{
int i = 0;
int j = (++i)+(i++);
printf("%d %d\n", j, i);
return 0;
}

使用了几个在线c++编译器测试:VC++的结果是2 2,符合预期;而g++的结果是3 2,跟事前的各种预期均不符,就好象两个都是先自增了一样,这可是为什么呢?

gcc -S test.c编译成汇编文件test.s看一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
        .file   "test.c"
.section .rodata
.LC0:
.string "%d %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) # 0 => i
addl $1, -8(%rbp) # 计算++i,保存结果到变量i
movl -8(%rbp), %eax # i => %eax,在之后的计算中用作i++前的i值
leal 1(%rax), %edx # 计算i++自增结果(这是gcc对i++常见的优化,等价于 movl %eax, %edx; addl $1, %edx)
movl %edx, -8(%rbp) # 保存结果到变量i
movl -8(%rbp), %edx # i => %edx, gcc认为这是++i之后的i值,然而它已在上一步中改变了
addl %edx, %eax # 计算%edx(++i后) + %eax(i++前)
movl %eax, -4(%rbp) # 保存结果到j
movl -8(%rbp), %edx
movl -4(%rbp), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf # printf
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
.section .note.GNU-stack,"",@progbits

所以,这个貌似两次都是先自增的计算结果,只是因为gcc提前计算并保存了i++的结果(副作用),并且重新加载了它当作++i的值罢了。换句话说,当它“不做任何特殊处理时,就是那样了”。

结论?为了您和家人的身心(DEBUG)健康,请只在独立的表达式中使用i++,或者,说广一点,任何带副作用的表达式。

python中没有++操作符,任何自增操作必须写为i += 1