C之位運算(十五)

        我們在嵌入式的開發中難免會遇到 C 語言中的位運算符,因爲我們需要效率,而位運算恰好效率比別的運算符效率高多了。位運算符直接對 bit 爲進行操作,其效率最高。常見的位運算操作如下

圖片.png

        我們在左移和右移時必須要注意:1、左操作數必須爲整數類型,char 和 short 被隱式轉換爲 int 後進行移位操作;2、右操作數的範圍必須爲:[0,31];3、左移運算符 << 將運算數的二進制位左移,規則是高位丟棄低位補0;4、右移運算符 >> 把運算數的二進制位右移,規則是高位補符號位低位丟棄。

        比如 0x1 << 2 + 3 的值會是多少呢?我們猜想有這麼幾種情況:1、先算 0x1 << 2 再把中間結果加 3,最終結果爲 7;2、先算 2 + 3,所以結果爲 32;3、這麼混合的運算會出錯。我們來看個示例代碼,來看看編譯器是如何處理的,代碼如下:

#include <stdio.h>

int main()
{
    printf("%d\n", 3 << 2); 
    printf("%d\n", 3 >> 1); 
    printf("%d\n", -1 >> 1); 
    printf("%d\n", 0x01 << 2 + 3);
    
    return 0;
}

        我們先來分析下這個代碼,第5行 3 << 2 ==> 11 << 2 ==> 1100 ==> 12;第6行 3 >> 1 ==> 11 >> 1 ==> 1;編譯後結果如下:

圖片.png

        我們可以看到我們的分析是對的,第8行執行的是我們之前分析的第2種結果。

        我們在 C 語言中應避免位運算符、邏輯運算符和數學運算符同時出現在一個表達式中;但位運算符、邏輯運算符和數學運算符需要同時參與運算時,儘量使用括號()來表達計算次序;左移 n 爲相當於乘以 2 的 n 次方(同理右移相當於除),但效率比數學運算符高。

        我們下來看個實現宏函數交換的功能,這也是筆試中經常會遇到的一個題目,代碼如下:

#define SWAP1(a, b)    \
{                      \
    int t = a;         \
    a = b;             \
    b = t;             \
}

        這是我們最常用的一種寫法,但是它需要一個額外變量。我們下面來看個不需要藉助額外變量的版本就可以完成的宏函數,代碼如下:

#define SWAP2(a, b)    \
{                      \
    a = a + b;         \
    b = a - b;         \
    a = a - b;         \
}

        第4 行相當於 b = (a + b) - b ==> b = a;第5行相當於 a = (a + b) - b ==> a = (a + b) - a ==> a = b;這種也可以完成交換功能,但是它的效率似乎不是那麼的高,因爲要藉助於數學運算。我們再來實現一個基於位運算實現的,代碼如下:

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

        我們上面的代碼效率是非常高的,我們來分析下,第 4 行相當於 b = (a ^ b) ^ b ==> b = a; 第5行相當於 a = (a ^ b) ^ b ==> a = (a ^ b) ^ a ==> a = b;這樣也實現了交換的功能。

        位運算與邏輯運算不同之處:1、位運算沒有短路規則,每個操作數都參與運算;2、位運算的結果爲整數,而不是 0 或 1;3、位運算的優先級高於邏輯運算優先級。

        我們來看看下面這個示例代碼:

#include <stdio.h>

int main()
{
    int i = 0;
    int j = 0;
    int k = 0;
    
    if( ++i | ++j & ++k )
    {
        printf("Run here...\n");
    }
    
    printf("i = %d\n", i);
    printf("j = %d\n", j);
    printf("k = %d\n", k);
    
    return 0;
}

        我們分析下,第 9 行執行完,i、j、k分別就是1了。因爲我們這塊是位運算,所以沒有短路規則。我們來看看編譯結果:

圖片.png

        是如我們分析的那樣,如果我們第9行換成if( ++i || ++j && ++k ) 這樣,那麼便是 i = 1,j = 0, k = 0 了,打印如下

圖片.png

        通過我們今天學習的位運算符,總結如下:1、位運算符只能用於整數類型;2、左移和右移運算符的右操作數範圍必須爲[0, 31];3、位運算沒有短路規則,所有操作數均會求值;4、位運算的效率高於四則運算和邏輯運算;5、運算優先級:四則運算 > 位運算 > 邏輯運算後面我們會繼續對 C 語言的學習。


         歡迎大家一起來學習 C 語言,可以加我QQ:243343083

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章