(i=-i++)你真的了解这个表达式么?

在这里我们先来看看如下的代码吧,环境是TurboC2.0,大家应该很熟悉的
1#include <stdio.h>
2
3int main()
4{
5    int i = 3;
6    i = -i++;
7    printf("%d", i);
8}
运行的结果是-2,为什么那?首先i为3,然后取反得-3,然后再++得-2,再赋值给i,打印出来就是-2.
以上红字部分是有错误的,经过“Ivony ”的讲解我明白了,正确的情况应该是:-i先得到一个临时的-3,然后把这个临时的-3赋值给i,然后再对i做++,得到-2。
这里保留原来的错误,算是给自己提个醒吧~!


好了下面来看看在C#中的情况吧~!
 1 using System;
 2 
 3 namespace ConsoleApplication3
 4 {
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9             int i = 3;
10             i = -i++;
11             Console.WriteLine(i);
12         }
13     }
14 }
15 

那么大家来猜猜结果会是多少?     答案是:-3。

很是奇怪是吧,怎么回事那?起初我也不是很明白,于是就到CSDN上发帖求问了(这里是CSDN的帖子地址),最初也没有什么能让我彻底明白的好的答案,但是有人提醒让我读读IL代码,于是我读了,分析了,明白了一些。后来有个叫Ivony(授人以鱼不如授人以渔,上海谋生)的回答,让我一下子有种醍醐灌顶的感觉。

正常,C#是先计算表达式的值,然后再执行自增操作。
所以

int i = 3;
i = -i++;

这里 -i++作为表达式,其值是-3,然后进行自增,i变成4,最后赋值,则i = -3。

……

 


为了更加深刻的理解,我把IL代码粘贴出来,然后分析一下

 1 .method private hidebysig static void  Main(string[] args) cil managed
 2 {
 3   .entrypoint
 4   // 代码大小       18 (0x12)
 5   .maxstack  3
 6   .locals init ([0] int32 i)
 7   IL_0000:  nop
 8   IL_0001:  ldc.i4.3
 9   IL_0002:  stloc.0
10   IL_0003:  ldloc.0
11   IL_0004:  dup
12   IL_0005:  ldc.i4.1
13   IL_0006:  add
14   IL_0007:  stloc.0
15   IL_0008:  neg
16   IL_0009:  stloc.0
17   IL_000a:  ldloc.0
18   IL_000b:  call       void [mscorlib]System.Console::WriteLine(int32)
19   IL_0010:  nop
20   IL_0011:  ret
21 // end of method Program::Main
22 

分析之前,先补充一点儿

nop

执行没有任何行为的操作

dup

重复位于堆栈顶端的值

add

将两个数值相加,并返回一个新数值

neg

对当前位于堆栈顶部的值执行求反

ret

从方法返回,可能返回一个值

call methodDesc

调用由methodDesc描述的方法

ldc.i4 num

将值num推送到堆栈上

stloc index

从堆栈中弹出一个值并将其存储在本地变量 index

ldloc index

将索引 index 处的局部变量加载到堆栈上

以下是对IL的分析

第一步:(ldc.i4.3)把值为3的数值放到堆栈中

第二步:(stloc.0)站顶元素3出站,赋值给变量i


以上就是i=3的语句执行过程。

 

第三步:(ldloc.0)把变量i的值读入堆栈顶


第四步:(dup)重复站顶元素3


第五步:(ldc.i4.1)把值为1的数值放到堆栈中


第六步:(add)将站顶两个数值相加,并返回一个新的数值,即4


第七步:(stloc.0)站顶元素出站赋值给变量i,因此此时变量i4


第八步:(neg)站顶元素执行求反操作

第九步:(stloc.0)把站顶元素-3出站,赋值给变量i,所以4被覆盖掉,i此时为-3

至此,完成第二行代码(i=-i++

 

第十步:(ldloc.0)把变量i的值-3读入站顶

第十一步:(call ……)调用打印方法,打印站顶元素

到此,屏幕上出现值为-3

 

至此,我的疑惑终于解决了,看来上学时没有学习编译原理真的是很大的一个遗憾啊,现在要通过自学补上了。

posted on 2007-07-25 21:08  啊不才  阅读(6401)  评论(20编辑  收藏  举报

导航