位运算符分析

1. C语言中的位运算符——直接对bit位进行操作,效率最高

&

按位与

|

按位或

^

按位异或

~

按位取反

<< 

左移

>> 

右移

2. 左移和右移注意点

(1)左操作数必须为整型类型:char和short被隐式转换为int后进行移位操作

(2)右操作数的范围必须为:[0,31]。其他值属未定义行为,不同编译器处理不同。

(3)左移运算符 << 将运算数的二进制位左移:规则为高位丢弃,低位补0

(4)右移运算符 >> 把运算数的二进制位左移:规则为高位补符号,低位丢弃

3. 有趣的问题:0x1 << 2 + 3 的值会是什么?

【实例分析】位运算符初探

#include <stdio.h>

int main()
{
    printf("%d\n", 3 << 2); //3<<2  ===> 0x11<<2 ===>1100,即12
    printf("%d\n", 3 >> 1); //0x11<<1, 即1
    printf("%d\n", -1 >> 1);//0x1111>>1 ,即0x1111,仍为1
    printf("%d\n", 0x01 << 2 + 3);//相当于0x01<<(2+3),即32
    
    printf("%d\n", 3 << -1); // oops!右操作数必须为[0,31],不同编译器处理方式不同
    
    return 0;
}

4. 小贴士——防错准则

(1)避免位运算符、逻辑运算符和数学运算符同时出现在一个表达式中

(2)当位运算符,逻辑运算符和数学运算符需要同时参与运算时,尽量使用括号()表达达计算次序。

【小技巧】

  ①左移n位相当于乘以2的n次方,但效率比数学运算符高

  ②右移n位相当于除以2的n次方,但效率比数学运算符高

【编程实验】交换两个整型变量的值

#include <stdio.h>

//利用中间变量交换
#define SWAP1(a, b)    \
{                      \
    int t = a;         \
    a = b;             \
    b = t;             \
}

//利用部分和来交换(当a和b很大的时候,a+b有可能溢出)
#define SWAP2(a, b)    \
{                      \
    a = a + b;         \
    b = a - b;         \
    a = a - b;         \
}

//利用异或运算(不可能溢出且效率高)
#define SWAP3(a, b)    \
{                      \
    a = a ^ b;         \
    b = a ^ b;         \     /* 相当于a^b^b=>a^0=>a */
    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;
}

5. 位运算与逻辑运算不同

(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); //1
    printf("j = %d\n", j); //1
    printf("k = %d\n", k); //1

    return 0;
}
#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); //1
    printf("j = %d\n", j); //0
    printf("k = %d\n", k); //0

    return 0;
}

面试题详解

  有一个数列,其中的自然数都是以偶数的形式出现,只有一个自然数出现的次数为奇数次,编写程序找出这个自然数。

思路一:①排序;②遍历数列并计数,找出

思路二:异或的方式

#include <stdio.h>
#define DIM(a) {sizeof(a)/sizeof(*a)}

int main()
{
     int a[] = {2, 3, 5, 7, 2, 2, 2, 5, 3, 7, 1, 1, 1};
     int find = 0;
    
     for(int i=0; i<DIM(a); i++)
    {
        find = find ^ a[i];
     }

    printf("find=%d\n",find);

    return 0;    
}

6. 小结

(1)位运算符只能用于整数类型

(2)左移和右移运算符的右操作数范围必须为[0,31]

(3)位运算的没有短路规则,所有操作数均会求值。

(4)位运算的效率高于四则运算和逻辑运算

(5)运算优先级: 四则运算 > 位运算 > 逻辑运算

posted on 2018-04-16 11:06  arabain  阅读(200)  评论(0)    收藏  举报

导航