java/C# 秒懂i++ 与 ++i
环境
c#
.net
值类型变量在赋值表达式中的运算法则
赋值表达式分为左值和右值,左值即为左边的变量,用来接收计算好的值,右边的值是一系列操作数和操作符计算后的结果值。
与在纸上代入变量计算右值不同,.net在计算右值时,会取出所有操作数变量的值,然后将他们入栈(可以理解为将实际变量的值保存到了栈中的一个临时的变量中),在栈中再将这些数与操作符进行计算返回给右值再赋值给左值。其目的是保证一个变量不会被表达式中其他的赋值运算符修改了变量的值,导致此变量在其他位置的值发生改变。
注意:赋值运算符会先将变量赋值,然后将变量值入栈。
举一个简单的例子
int a =10;
a=a+(a=100);//a=110
根据以上的规则,可以推演其计算右值的步骤:a值入栈,其次,将a变量的值变为100,最后变为100的变量a 的 值入栈。由于栈中的值与变量已经毫无关系所以a=10+100;
第二个例子
int a=10;
int b=11;
a=b+a+(b=100)*0+(a=100)*0;//a=21
推演:b值入栈,a值入栈,b赋值为100,然后b的值入栈;再然后a赋值为100然后其值入栈,将栈中的值代入公式为:11+10+100x0+100x0=21
i++ 与 ++i 在赋值表达式的运算规则
首先,这两者在独占一行语句时,两者的效果都是一样的
//两者在单独作为一条语句时,执行的结果一致。
i++;
++i;
当单独占一行语句时,.net 编译的CLR会将两者编译成完全一样的中间语句,由于,JVM 与 CLR 输出的中间语句机制差不多(并不严谨),所以java 在有关 i++ 与 ++i 的相关处理,也完全一致。
当在赋值表达式中:由于++运算符的优先级比 + - / * 的运算符等级高,所以,在将变量值入栈时会有变化。i++会将i先入栈,**入栈之后,再将i变量的值+1;**而++i 会先将i变量的值+1,然后入栈。
第三个例子
int a=10;
int b=10;
a=a++;//10
b=++b;//11
根据++在赋值表达式的运算规则,右值a先入栈,然后变量a自增,a的值变为11;所有变量入栈之后(这里只有一个变量a),开始代入操作符开始计算(此例子也没操作符),然后赋值:a=10,所以a=a++等于10;
再看看b=++b: 首先b先自增,导致变量b的值为11,然后b值入栈,最后出栈直接赋值给b:b=11;
第四个例子
int a=10;
int b=10;
int c=10;
c=a++ + b + a;//c=31
推演:a值入栈,然后a变量+1;b值入栈;第三个操作数的a因为被第一项操作数的a++赋值导致a等于11,所以11入栈,将栈中的值代入操作符:c=10+10+11;
第五个例子
int a=10;
int b=10;
int c=10;
c=++a +b +a;//c=32
与第三个例子不同,第一个操作数由a++ 变为++a,所以在第一个操作数入栈之前,a的值先被+1
仅用一行代码交换两个值变量的值
利用栈中的临时变量来交换两个值变量的值
//交换ab变量
int a = 10;
int b = 11;
a = b + (b = a) * 0;
Console.WriteLine(a)//11;
Console.WriteLine(b)//10;
推演:b值入栈,b被a赋值,即b=10,然后b值入栈。该入栈的入栈之后,开始出栈代入操作符:a=11+10x0,即a=11;成功交换
同样可以适用于两个字符串变量的交换
string aa = "aa";
string bb = "bb";
aa = bb + (bb = aa).Remove(0);
推演:bb值入栈,bb变量的值变为“aa”,然后bb值入栈,将栈中变量出栈代入操作符,注意,关系运算符 . 的优先级最高,所以要计算(bb = aa).Remove(0),其返回值为空,那么最后aa=bb+"";成功交换
在c或c++ 中,针对 ++ 运算符的处理将有所不同可以看看参考文档(最后一段):https://blog.csdn.net/ffanfanm/article/details/12784489