【C進階】16、位運算子

bryson發表於2021-10-14

Summary

1)C語言中的位運算子:

運算子意義規則
&按位與全1得1,有0得0
I按位或有1得1,全0得0
^按位異或相同為0,不同得1
~取反1變0, 0變1
<<左移高位丟棄,低位補0
·>>右移高位補符號位,低位捨棄

2)左移、右移的注意點:

  • 左運算元必須是整數型別

    • char和short被隱式轉換為int後進行操作
  • 右運算元的範圍必須為:[0,31]否則結果未定義(不同編譯器處理結果不同)
  • 左移運算子<<將運算數的二進位制位左移,效果相當於乘以2的n次方效率更高
  • 右移運算子>>將運算數的二進位制位右移,效果相當於除以2的n次方效率更高
  • 避免位運算子、邏輯運算子、數學運算子等混合運算,如果必須這樣,使用括號表示好計算順序。(單算移比、按邏三賦

3)位運算注意點:

  • 位運算沒有短路規則,每個運算元都會參與運算
  • 位運算的結果是整數,而不是0或1
  • 位運算的優先順序高於邏輯運算(單算移比 按邏三賦

4)交換兩個整形變數的值:

  • Demo1:部分和方式:不使用中間變數,但存在溢位的問題

    #define SWAP(a, b) \
    {                  \
      a = a + b;       \
      b = a - b;       \
      a = a - b;       \
    }
  • Demo2:位運算方式:使用異或(兩個相同的值異或結果為0,任何數和0異或仍為本身

    #define SWAP(a, b)    \
    {                     \
      a = a ^ b;          \
      b = a ^ b;          \
      a = a ^ b;          \
    }

位運算子剖析

C語言最初設計用來開發UNIX作業系統,作業系統執行於硬體平臺之上,必然會涉及位運算,需要對硬體的bit位(0和1)進行操作。C語言中位運算直接對映到了硬體系統中的位運算。
位運算子直接對bit位進行操作,其效率最高

1、C語言中的位運算子

運算子意義規則
&按位與全1得1,有0得0
I按位或有1得1,全0得0
^按位異或相同為0,不同得1
~取反1變0, 0變1
<<左移高位丟棄,低位補0
·>>右移高位補符號位,低位捨棄

2、左移和右移的注意點

  • 左運算元必須是整數型別

    • char和short被隱式轉換為int後進行操作
  • 右運算元的範圍必須為:[0,31]否則結果未定義(不同編譯器處理結果不同)
  • 左移運算子<<將運算數的二進位制位左移,效果相當於乘以2的n次方效率更高
  • 右移運算子>>將運算數的二進位制位右移,效果相當於除以2的n次方,效率更高

    • Demo1
      d << 2;               // error, 左運算元必須是整型
      int x = 10 >> 1;      // ok,"右移等效除以2的n次方",輸出5
      int y = -1 << 1;      // ok,"左移等效乘以2的n次方",輸出-2
    
      int z = 3 << -1;      // -1不在[0,31]範圍中,結果未定義,不同編譯器不同處理
              // 編譯器亦提示了錯誤:Possible overflow in shift operation
      
      // gcc 1,            左移-1相當於右移1,那就除以2,得到了1
      // bcc -2147483648,  int的最小值
      // vc 0,             本來就未定義,給你0把
  • 避免位運算子、邏輯運算子、數學運算子等混合運算,如果必須這樣,使用括號表示好計算順序。(單算移比、按邏三賦

    • Demo2
    0x1 << 2 + 3 輸出多少?
    等價於 0x1 << (2 + 3),輸出為32
    
    // 如果這行程式碼作者本意是先左移,再加法,實際執行結果就不是期望的
    // 所以在寫程式碼時要儘量用括號()來表示清楚計算次序

3、位運算注意點

  • 位運算沒有短路規則,每個運算元都會參與運算
  • 位運算的結果是整數,而不是0或1
  • 位運算的優先順序高於邏輯運算(單算移比 按邏三賦

    int i = 0;
    int j = 0;
    int k = 0;
    
    if(++i | ++j & ++k)        // 所有的運算數都會執行到,因此i j k判斷後都為1
      printf("cc");

4、 位運算應用簡單示例

交換兩個整形變數的值

  • Demo1:部分和方式:不使用中間變數,但存在溢位的問題

    #define SWAP(a, b) \
    {                  \
      a = a + b;       \
      b = a - b;       \
      a = a - b;       \
    }
  • Demo2:位運算方式:使用異或(兩個相同的值異或結果為0,任何數和0異或仍為本身

    #define SWAP(a, b)    \
    {                     \
      a = a ^ b;          \
      b = a ^ b;          \
      a = a ^ b;          \
    }

本文總結自“狄泰軟體學院”唐佐林老師《C語言進階課程》。
如有錯漏之處,懇請指正。

相關文章