Chinaunix首页 | 论坛 | 博客
  • 博客访问: 22661
  • 博文数量: 8
  • 博客积分: 1410
  • 博客等级: 上尉
  • 技术积分: 141
  • 用 户 组: 普通用户
  • 注册时间: 2008-01-20 00:03
文章分类
文章存档

2011年(1)

2008年(7)

我的朋友
最近访客

分类: C/C++

2008-04-04 16:53:23

最近在恶补C/C++的基础知识。一直以来,遇到一些与编译器相关的小程序时,我往往都迷惑不解,每每思索都不得要领。最近一个同学告诉我用反汇编来查看编译的代码,什么都会变得清楚明朗。
 
从一个例子引起的问题:
 

int k = 1;
printf("%d\n",(++k)+(++k));


   这个例子是我一个朋友发给我的,他告诉我他一直都想不通为什么在VC6.0下面会输出6。我接过例子的时候也以为结果是5,至少我在GNU Gcc下面编译运行是5。可是VC6.0下面输出却是6。
   这回,我编译后用debug调试,打开disassembly查看汇编代码。的确,一看汇编后,什么事情都变得明朗。

25: int k = 1;
0040D799 mov dword ptr [ebp-10h],1
26:
27: printf("%d\n",(++k)+(++k));
0040D7A0 mov edx,dword ptr [ebp-10h]
0040D7A3 add edx,1
0040D7A6 mov dword ptr [ebp-10h],edx
0040D7A9 mov eax,dword ptr [ebp-10h]
0040D7AC add eax,1
0040D7AF mov dword ptr [ebp-10h],eax
0040D7B2 mov ecx,dword ptr [ebp-10h]
0040D7B5 add ecx,dword ptr [ebp-10h]
0040D7B8 push ecx
0040D7B9 push offset string "%d\n" (00422f9c)
0040D7BE call printf (0040d6e0)


    ebp是运行时堆栈的栈低指针。ebp-10h地址上存放了k的值([ebp-10h]表示ebp-10h地址上的内容),运行int k = 1;后,[ebp-10h]的值是1。
    接着运行printf("%d\n",(++k)+(++k));语句。printf()实际上是库函数,在调用printf()函数前,需要先计算(++k)+(++k)的值,然后把该值压到栈顶,以传送给printf()的形参。
    关键还是(++k)+(++k)的计算问题。
    C语言中只有四个运算存在规定的求值顺序:&&、||、?:和,(注意:此处的,是逗号操作符,并非函数参数列表的分隔符,)。
   由于()的优先级作用,会先计算++k,但是并没有规定两边(++k)的求值顺序。所以,有可能是左边的++k先求值,也有可能是+右边的++k先求值。但无论如何,两次的++k之后,k的值是3 。然而,为何计算结果为什么不是2 + 3 或者是 3 + 2 呢?这似乎与求值顺序无关。
   但是,编译器似乎没有预计得到,计算其中一边的表达式算影响到另一边的表达式的结果。所以,编译器认为两边的++k是相等的。

   mov edx,dword ptr [ebp-10h] //把k的值放到edx寄存器中
   add edx,1  //计算++k
   mov dword ptr [ebp-10h],edx   //再把++k的结果放回ebp-10h地址中,此时k=2
   mov eax,dword ptr [ebp-10h]  //把k值复制到eax寄存器中
   add eax,1  //计算++k
   mov dword ptr [ebp-10h],eax  //再把++k的结果放回ebp-10h地址中,此时k=3
   mov ecx,dword ptr [ebp-10h]  //把k值复制到ecx中
   add ecx,dword ptr [ebp-10h]  //计算k+k的值
   push ecx //将k+k的值压栈,以传送给printf的形参
   听说,这个现象叫做存储器别名使用(memory aliasing)。反正,不要这么用就可以避免了。

阅读(876) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:基于s3c2410软中断服务的uC/OS-II任务切换

给主人留下些什么吧!~~