位运算

位运算符简介

位运算符直接对bit位进行操作,其效率最高,C语言支持以下位运算符。

位运算符 作用
& 按位与
\ 按位或
^ 按位异或
~ 按位取反
<< >> 左右移运算
<<< >>> 左右移运算

左右移运算的规则

左操作数必须为整形类型,不能为浮点类型,char和short被隐式转换为int后进行以为操作。
右操作数的范围必须为[0, 31]之间的整数。
以上是标准C规范的定义,不同编译器可能有不同的实现,比如某些编译器循序右操作数范围为32,某些编译器下右操作数为负数也能够编译通过,这种情况应尽量避免。
左移运算符<<将运算数的二进制位左移,规则是高位丢弃,低位补0。
右移运算符>>将运算数的二进制位右移,规则是高位补符号位,低位丢弃。
测试代码:

int main(void) {
    float f = 1.0;

//    printf("0x%08x\n", f << 4);        // error
//    printf("0x%08x\n", 0x0001 << 1.4);      // error
    printf("0x%08x\n", 0x0001 << 4);    // 0x00000010
    printf("0x%08x\n", 0x00010000 >> 4);    // 0x00001000
    printf("0x%08x\n", -16);        // 0xfffffff0
    printf("0x%08x\n", -16 >> 4);        // 0xffffffff
    printf("0x%08x\n", -16 >> -4);        // 不同编译器的处理结果不同
    printf("%d\n", 1 << 2 + 3);        // 32
    while (1);
}

防错准则:

避免位运算符、逻辑运算符和数学运算符同时出现在一个表达式中。当位运算符、逻辑运算符和数学运算符需要同时参与运算时,尽量使用括号()来表达计算次序。
小技巧:
左移n位相当于乘以2的n次方,但效率比数学运算符高
右移n位相当于除以2的n次方,但效率比数学运算符高

位运算与逻辑运算的区别

位运算与逻辑运算的不同:
位运算没有短路原则,每个操作数都参与运算。
位运算的结果为整数,而不是1或0。
位运算的优先级高于逻辑运算优先级。

测试代码

int main(void) {
    int i = 0;
    int j = 0;
    int k = 0;

    if (++i | ++j & ++k) {
        printf("Running\n");
    }
    printf("i = %d, j = %d, k = %d\n", i, j, k);        

    int x = 0;
    int y = 0;
    int z = 0;

    if (++x || ++y && ++z) {
        printf("Running\n");
    }
    printf("x = %d, y = %d, z = %d\n", x, y, z);
    while (1);
}

运行结果

Running
i = 1, j = 1, k = 1
Running
x = 1, y = 0, z = 0

位运算的作用

节省内存

同样的内存空间使用位运算来存储更多的信息

提高效率

由于位运算是CPU中的指令集,所以他的运算效率是最高的,可以用位运算来提高乘除法的效率

其他骚操作

使用位运算实现两个数交换值

#include <stdio.h>

#define SWAP0(a, b) {    \
    int temp = a;        \
    a = b;                \
    b = temp;            \
}

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

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

int main(void) {
    int a = 1;
    int b = 3;

    printf("a = %d, b = %d\n", a, b);    
    SWAP0(a, b);
//    SWAP1(a, b);
//    SWAP2(a, b);
    printf("a = %d, b = %d\n", a, b);        
    while (1);
}

使用位运算统计二进制数0/1的数量

总结

位运算符只能用于整数类型。
右移和左移运算符的右操作数范围必须为[0, 32]
位运算没有短路原则,所有操作数均会求值。
位运算的效率高于四则运算和逻辑运算
运算优先级:四则运算 > 位运算 > 逻辑运算


   转载规则


《位运算》 rookiegan 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
有符号数和无符号数 有符号数和无符号数
与java语言不同,在C/C++语言中有着有符号数与无符号数的概念,有符号数可以表示正数、0、负数,无符号数只能表示非负数。数据位数相同的有符号数和无符号数所能表示的数据个数是一样的,但由于有符号数最高位为符号位,两者表示的数字的区间不同。
2017-11-03
下一篇 
C语言变量的属性 C语言变量的属性
C语言中的变量可以有自己的属性,在定义变量是可以加上属性关键字,属性关键字指明变量有着特殊的含义。C语言中有着auto、register、static、const、extern等属性关键字。 autoauto是C语言中局部变量的默认属性,a
2017-09-08 rookiegan
  目录