c# 連等算式都在做什么


在研究兩個整數互換的方法時(詳細看這里),發現了一個有趣的現象。

a ^= b ^= a ^= b;      a ^= b;b ^= a;a ^= b;

有興趣的童鞋可以看看下面代碼的結果是什么:

int a = 10;
int b = 5;
a ^= b ^= a ^= b;
Console.WriteLine("{0}  {1}", a, b);

一直以為a=b=c就是按照先后順序執行b=c,a=b。照上面的執行結果來看,還不一定。

到底執行的順序怎么樣,要看看反編譯的代碼才知道。

 

先看看a=b=c=30都在做什么:

IL_0008:  ldc.i4.s   30 //推送30到棧頂端
IL_000a:  dup           //復制一個30到棧頂端
IL_000b:  stloc.2       //提取頂端的30賦值給索引為2的變量,也就是c
IL_000c:  dup           //復制一個棧頂端的30
IL_000d:  stloc.1       //提取頂端的30賦值給索引為1的變量,也就是b
IL_000e:  stloc.0       //提取頂端的30賦值給索引為0的變量,也就是a

這樣來看,a=b=c=30可以理解成c=30,b=30,a=30.

 

再看看a ^= b ^= a ^= b在做什么(初始化這里a=10,b=5):

IL_0006:  ldloc.0 //推送索引為0的變量值到棧頂端,也就是10
IL_0007:  ldloc.1 //推送5
IL_0008:  ldloc.0 //推送10 
IL_0009:  ldloc.1 //推送5
IL_000a:  xor     //提取10和5,做異或運算,將結果15推送到棧頂端 
IL_000b:  dup     //復制15
IL_000c:  stloc.0 //提取15賦值給a
IL_000d:  xor     //取頂端的兩個值15和5,做異或運算,將結果10推送到棧頂端
IL_000e:  dup     //復制10
IL_000f:  stloc.1 //提取10賦值給b
IL_0010:  xor     //取頂端的兩個值10和10做異或運算,結果0放到棧頂端
IL_0011:  stloc.0 //提取0賦值給a

做圖解如下(作圖水平不高,但應該勉強能看懂):

整個過程,用代碼還原就是

    a1=a0^b0=15;

然后  b1=b0^a1=10;

再然后 a2=a0^b1=10^10=0。

前面兩步的環節基本上是我們想要的,但是第三步a2=a0^b1卻脫離了我們的原意,這里采用了a0做異或而不是a1,所以對應的結果也就出現了偏差。

因此,這一行代碼執行下來,a=0,b=10,結果顯然並不是我們想要的。

 

接下來,再看看a ^= b;b ^= a;a ^= b;在干嘛:

IL_0006:  ldloc.0  //推送10
IL_0007:  ldloc.1  //推送5
IL_0008:  xor      //提取10和5做異或運算,得15,推送至棧頂
IL_0009:  stloc.0  //將15賦值給a
IL_000a:  ldloc.1  //推送b的值5
IL_000b:  ldloc.0  //推送a的新值15
IL_000c:  xor      //提取15和5做異或運算,得10,推送至棧頂
IL_000d:  stloc.1  //將10賦值給b
IL_000e:  ldloc.0  //推送a的值15
IL_000f:  ldloc.1  //推送b的新值10
IL_0010:  xor      //提取15和10做異或運算,得5,推送至棧頂
IL_0011:  stloc.0  //將5賦值給a

整個過程比較清晰。中規中矩的異或計算然后賦值,再異或,再賦值,再異或賦值。最后a=5,b=10,結果和我們想的一樣。

 

C#里面可以寫連等句式,但是其中的邏輯一定要小心,尤其是連等過程中有變量賦值的,更要注意。平時使用的時候,建議不要為了省那兩行的代碼量而用連等語句拼湊,因為運算的結果可能和我們想要的不一樣,而導致程序bug,得不償失。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM