交換a,b值的C#各種寫法


通常swap(a,b),都是用中間變量

public static void Swap1(ref int a, ref int b)
        {
            int temp = a;
            a = b;
            b = temp;
        }

生成的IL如下(去除ref)

 .maxstack 1
    .locals init (
        [0] int32 temp)
    L_0000: ldarg.0 
    L_0001: stloc.0 
    L_0002: ldarg.1 
    L_0003: starg.s a
    L_0005: ldloc.0 
    L_0006: starg.s b
    L_0008: ret 

如果面試官問你不適用任何第三方變量,那么可以這樣

public static void Swap2(ref int a, ref int b)
        {
            a = a + b;
            b = a - b;
            a = a - b;
        }

這樣做,a+b可能超出范圍,拋異常。所以得用位運算。

public static void Swap3(ref int a, ref int b)
        {
            a ^= b;
            b ^= a;
            a ^= b;
        }

哇,位運算高效么?計算機原理總是說位運算是最快的。沒錯!!!

可是,C#作為高級語言,性能跟生成的最終指令有關系,我們往往忽略了編譯器生成的最終指令。

位運算一看就是三組運算,生成IL如下:

.method public hidebysig static void Swap3(int32 a, int32 b)cilmanaged
{
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: ldarg.1 
    L_0002: xor 
    L_0003: starg.s a
    L_0005: ldarg.1 
    L_0006: ldarg.0 
    L_0007: xor 
    L_0008: starg.s b
    L_000a: ldarg.0 
    L_000b: ldarg.1 
    L_000c: xor 
    L_000d: starg.s a
    L_000f: ret 
}

可見,比第一種用臨時變量生成的IL要多不少,所以可以得出其速度慢於temp交換。事實的性能測試,也證明了如此。

其實還有一種更為巧妙的swap

public static void Swap4(ref int a, ref int b)
        {
            b = a + 0 * (a = b);
        }

生成的IL十分詭異:

.maxstack 8
    L_0000: ldarg.0 
    L_0001: ldarg.1 
    L_0002: starg.s a
    L_0004: starg.s b
    L_0006: ret 

奇怪,怎么a=b; b=a;就可以實現了?

好吧,其實我們又被編譯器給欺騙了,最終生成的匯編指令是這樣的么?

(話說,我還不知道如何看C#生成的匯編指令,不知道哪個大牛告訴一下?)

通過一番蛋疼的性能測試。

我得出一個結論:

  位運算交換——慢。

  temp交換——非常快。

  詭異的交換——非常快。與temp不相上下,當然,百億級的測試,還是temp微弱優勢取勝。

 

其實,那個詭異的方法,最終也是寄存器交換操作,生成的機器指令應該和temp是一樣的。當然,這是我猜測的。O(∩_∩)O哈!

 


免責聲明!

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



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