(i=-i++)你真的了解这个表达式么?
#include <stdio.h>2

3
int main()4
{5
int i = 3;6
i = -i++;7
printf("%d", i);8
}以上红字部分是有错误的,经过“Ivony ”的讲解我明白了,正确的情况应该是:-i先得到一个临时的-3,然后把这个临时的-3赋值给i,然后再对i做++,得到-2。
这里保留原来的错误,算是给自己提个醒吧~!
好了下面来看看在C#中的情况吧~!
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++作为表达式,其值是-3,然后进行自增,i变成4,最后赋值,则i = -3。
|
为了更加深刻的理解,我把IL代码粘贴出来,然后分析一下
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 处的局部变量加载到堆栈上 |
第一步:(ldc.i4.3)把值为3的数值放到堆栈中
第二步:(stloc.0)站顶元素3出站,赋值给变量i
以上就是i=3的语句执行过程。
第三步:(ldloc.0)把变量i的值读入堆栈顶
第四步:(dup)重复站顶元素3
第五步:(ldc.i4.1)把值为1的数值放到堆栈中
第六步:(add)将站顶两个数值相加,并返回一个新的数值,即4
第七步:(stloc.0)站顶元素出站赋值给变量i,因此此时变量i为4
第八步:(neg)站顶元素执行求反操作
第九步:(stloc.0)把站顶元素-3出站,赋值给变量i,所以4被覆盖掉,i此时为-3
至此,完成第二行代码(i=-i++)
第十步:(ldloc.0)把变量i的值-3读入站顶
第十一步:(call ……)调用打印方法,打印站顶元素
到此,屏幕上出现值为-3。
至此,我的疑惑终于解决了,看来上学时没有学习编译原理真的是很大的一个遗憾啊,现在要通过自学补上了。


浙公网安备 33010602011771号