(++i)+(++i)+(++i)+(++i)
今天,看到一个面试题,居然无聊到这种地步,看这代码:
下载: test.c
- #include<stdio.h>
- main()
- {
- int i=1,j;
- j=(++i)+(++i)+(++i)+(++i);
- printf("%d\n",j);
- }
问输出的j是多少。。。虽然知道这个很无聊,但是反正闲着也是闲着嘛,就研究了下,执行
lly@LLY:~/test$ gcc test.c
lly@LLY:~/test$ ./a.out
15
lly@LLY:~/test$ ./a.out
15
这我就不懂了。。。再看看objdump的结果:
lly@LLY:~/test$ objdump -d a.out
...省略若干
8048385: c7 45 f4 01 00 00 00 movl $0x1,0xfffffff4(%ebp)
804838c: 83 45 f4 01 addl $0x1,0xfffffff4(%ebp)
8048390: 83 45 f4 01 addl $0x1,0xfffffff4(%ebp)
8048394: 8b 45 f4 mov 0xfffffff4(%ebp),%eax
8048397: 03 45 f4 add 0xfffffff4(%ebp),%eax
804839a: 83 45 f4 01 addl $0x1,0xfffffff4(%ebp)
804839e: 03 45 f4 add 0xfffffff4(%ebp),%eax
80483a1: 83 45 f4 01 addl $0x1,0xfffffff4(%ebp)
80483a5: 03 45 f4 add 0xfffffff4(%ebp),%eax
80483a8: 89 45 f8 mov %eax,0xfffffff8(%ebp)
...省略若干
...省略若干
8048385: c7 45 f4 01 00 00 00 movl $0x1,0xfffffff4(%ebp)
804838c: 83 45 f4 01 addl $0x1,0xfffffff4(%ebp)
8048390: 83 45 f4 01 addl $0x1,0xfffffff4(%ebp)
8048394: 8b 45 f4 mov 0xfffffff4(%ebp),%eax
8048397: 03 45 f4 add 0xfffffff4(%ebp),%eax
804839a: 83 45 f4 01 addl $0x1,0xfffffff4(%ebp)
804839e: 03 45 f4 add 0xfffffff4(%ebp),%eax
80483a1: 83 45 f4 01 addl $0x1,0xfffffff4(%ebp)
80483a5: 03 45 f4 add 0xfffffff4(%ebp),%eax
80483a8: 89 45 f8 mov %eax,0xfffffff8(%ebp)
...省略若干
里面的0xfffffff4 是变量i,0xfffffff8是j,可以看出现在是先把i自加2次,再取出两个i的值相加(这时候两个i的值都是3),再执行后面的,也就是 3+3+4+5 = 15。不解,于是用了另一个编译器(小型的tcc)编译,执行,结果就不一样了:
lily@LLY:~/test$ tcc test.c
lily@LLY:~/test$ ./a.out
14
lily@LLY:~/test$ ./a.out
14
也看看关键的汇编代码:
....
80481ed: b8 01 00 00 00 mov $0x1,%eax
80481f2: 89 45 fc mov %eax,-0x4(%ebp)
80481f5: 8b 45 fc mov -0x4(%ebp),%eax
80481f8: 83 c0 01 add $0x1,%eax
80481fb: 89 45 fc mov %eax,-0x4(%ebp)
80481fe: 8b 4d fc mov -0x4(%ebp),%ecx
8048201: 83 c1 01 add $0x1,%ecx
8048204: 89 4d fc mov %ecx,-0x4(%ebp)
8048207: 01 c8 add %ecx,%eax
8048209: 8b 4d fc mov -0x4(%ebp),%ecx
804820c: 83 c1 01 add $0x1,%ecx
804820f: 89 4d fc mov %ecx,-0x4(%ebp)
8048212: 01 c8 add %ecx,%eax
8048214: 8b 4d fc mov -0x4(%ebp),%ecx
8048217: 83 c1 01 add $0x1,%ecx
804821a: 89 4d fc mov %ecx,-0x4(%ebp)
804821d: 01 c8 add %ecx,%eax
804821f: 89 45 f8 mov %eax,-0x8(%ebp)
...
80481ed: b8 01 00 00 00 mov $0x1,%eax
80481f2: 89 45 fc mov %eax,-0x4(%ebp)
80481f5: 8b 45 fc mov -0x4(%ebp),%eax
80481f8: 83 c0 01 add $0x1,%eax
80481fb: 89 45 fc mov %eax,-0x4(%ebp)
80481fe: 8b 4d fc mov -0x4(%ebp),%ecx
8048201: 83 c1 01 add $0x1,%ecx
8048204: 89 4d fc mov %ecx,-0x4(%ebp)
8048207: 01 c8 add %ecx,%eax
8048209: 8b 4d fc mov -0x4(%ebp),%ecx
804820c: 83 c1 01 add $0x1,%ecx
804820f: 89 4d fc mov %ecx,-0x4(%ebp)
8048212: 01 c8 add %ecx,%eax
8048214: 8b 4d fc mov -0x4(%ebp),%ecx
8048217: 83 c1 01 add $0x1,%ecx
804821a: 89 4d fc mov %ecx,-0x4(%ebp)
804821d: 01 c8 add %ecx,%eax
804821f: 89 45 f8 mov %eax,-0x8(%ebp)
...
可以看到这里面的-0x4(%ebp) 是i,而 -0x8(%ebp)是j。而之前的两次自加操作分别是在 %eax 和 %ecx 上执行的,第一次相加操作就是直接把这两个寄存器里面的值加在一起了。所以最终的效果相对于 2+3+4+5 = 14 。
这样的结果说明了同样的C代码,在不同的编译器下,会产生完全不同的可执行文件,当然如果你的源代码写得不好,完全有可能产生不同的执行结果。另外也再一次说明了这样一个面试题的无聊性,作为反面教材还差不多,嘿嘿。
BTW: 有兴趣的朋友还可以自行研究一下 (++i)+(++i)+(i++)+(i++)+(++i) 的执行结果。
tlhl28 在 2007年12月17日 17:58 说:【 】
呵呵~~~
那时候在论坛问了,对这代码评价不太好…….
Burgess 在 2010年01月18日 14:17 说:【 】
Turbo-C下运行结果为20