bones7456 all linux

Archive for 12月 8th, 2007

(++i)+(++i)+(++i)+(++i)

今天,看到一个面试题,居然无聊到这种地步,看这代码:

下载: test.c
  1. #include
  2. main()
  3. {
  4.         int i=1,j;
  5.         j=(++i)+(++i)+(++i)+(++i);
  6.         printf("%d\n",j);
  7. }

问输出的j是多少。。。虽然知道这个很无聊,但是反正闲着也是闲着嘛,就研究了下,执行

lly@LLY:~/test$ gcc test.c
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)
...省略若干

里面的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

也看看关键的汇编代码:

....
 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)
...

可以看到这里面的-0×4(%ebp) 是i,而 -0×8(%ebp)是j。而之前的两次自加操作分别是在 %eax 和 %ecx 上执行的,第一次相加操作就是直接把这两个寄存器里面的值加在一起了。所以最终的效果相对于 2+3+4+5 = 14 。
这样的结果说明了同样的C代码,在不同的编译器下,会产生完全不同的可执行文件,当然如果你的源代码写得不好,完全有可能产生不同的执行结果。另外也再一次说明了这样一个面试题的无聊性,作为反面教材还差不多,嘿嘿。

BTW: 有兴趣的朋友还可以自行研究一下 (++i)+(++i)+(i++)+(i++)+(++i) 的执行结果。