C语言 位运算符

C 语言支持的位运算符直接对bit位进行操作,其效率最高,总共有6种位运算符:

位运算符

假设变量 A 的值为 60,变量 B 的值为 13,则:

运算符 描述 实例
& 按位与操作,按二进制位进行”与”运算。运算规则:0&0=0; 0&1=0; 1&0=0; 1&1=1; (A & B) 将得到 12,即为 0000 1100
| 按位或运算符,按二进制位进行”或”运算。运算规则:0|0=0; 0|1=1; 1|0=1; 1|1=1; (A | B) 将得到 61,即为 0011 1101
^ 异或运算符,按二进制位进行”异或”运算。运算规则:0^0=0; 0^1=1; 1^0=1; 1^1=0; (A ^ B) 将得到 49,即为 0011 0001
~ 取反运算符,按二进制位进行”取反”运算。运算规则:~1=0; ~0=1; (~A ) 将得到 -61,即为 1100 0011,一个有符号二进制数的补码形式。
<< 二进制左移运算符。将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。 A << 2 将得到 240,即为 1111 0000
>> 二进制右移运算符。将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。 A >> 2 将得到 15,即为 0000 1111

左移和右移

左移和右移注意点

  • 左操作数必须为整数类型:char和short被隐式转换为int后进行移位操作
  • 右操作数的范围为:[0,31] (32bit操作系统),如果右操作数小于0,则会产生随机的结果
  • 左移运算符<<将运算数的二进制位左移,移动规则是:高位丢弃,低位补0
  • 右移运算法>>将运算数的二进制位右移,移动规则是:高位补符号位,低位丢弃

示例:位运算符初探

#include <stdio.h>

int main()
{
    printf("%d\n", 3 << 2); 
    printf("%d\n", 3 >> 1); 
    printf("%d\n", -1 >> 1); // -1所有位都是1, 右移还都是1
    printf("%d\n", 0x01 << 2 + 3); // 位运算符 优先级低于 四则运算符

    printf("%d\n", 3 << -1); // oops!,具体的结果由编译器决定,为不确定值

    return 0;
}

gcc运行结果:

C语言位运算符初探

vc10.0运行结果,可知3 << -1的结果为0:

C语言位运算符初探

位运算法使用技巧

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

示例:交换两个整型变量的值

如何不借助第三个临时变量来交换两个整型?

SWAP1显示不满足要求了。

SWAP2虽然没有借助中间变量,但当a和b都是非常大的整数时,那么相加后的结果可能会产生溢出,这时,这种方法还是有问题。

SWAP3才是最完美的写法!

#include <stdio.h>

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

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

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

int main()
{
    int a = 1;
    int b = 2;


    printf("a = %d\n", a); 
    printf("b = %d\n", b); 

    SWAP3(a ,b);

    printf("a = %d\n", a); 
    printf("b = %d\n", b); 

    return 0;
}

运行结果:

C语言位运算符

位运算符与逻辑运算符

位运算符与逻辑运算符的不同

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

示例:混淆概念的判断条件

#include <stdio.h>

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

    if( ++i | ++j & ++k )
    {
        printf("Run here...\n");
    }

    return 0;
}

运行结果:

C语言位运算符

i,j,k的值也都是1了,也就是说为运算符没有短路规则,注意不要与||,&&混淆了概念。

总结

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

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程

C语言教程