16-位运算符分析

注:博客中内容主要来自《狄泰软件学院》,博客仅当私人笔记使用。

测试环境:Ubuntu 10.10

GCC版本:4.4.5

一、位运算符分析

1)C语言中的位运算符

     位运算符直接对bit位进行操作,其效率最高。

2)左移和右移注意点

  - 左操作数必须为整数类型

    *char 和 short被隐式转换为int后进行移位操作

  - 右操作数的范围必须为:[0,31]

  - 左移运算符<<将运算数的二进制位左移

    *规则:高位丢弃,低位补0

  - 右移运算符>>把运算符的二进制位右移

    *规则:高位补符号位,低位丢弃

二、有趣的问题

1)0x1<<2 + 3的值会是什么? 

分析:考察的是优先级问题

   A同学:先算0x1 << 2 再把中间结果为3,最终为7。

   B同学:我觉得先算2 + 3,所以结果为32。

   C同学:可以这么混合计算吗?

问题:

        原作者的本意究竟想表达什么?

实例分析
位运算符初探
16-1.c

#include <stdio.h>

int main()
{
    printf("%d\n", 3 << 2); 	    //11<<2 ==> 1100 ==> 12
    printf("%d\n", 3 >> 1); 	    //11>>1 ==> 01 ==> 1
    printf("%d\n", -1 >> 1);        //-1==>补码:0xffff,右移1位:0xffff==>-1
    printf("%d\n", 0x01 << 2 + 3);  //0x01<<(2 + 3) = 32
    
    //printf("%d\n", 3 << -1); // oops!    gcc显示1
    
    return 0;
}

操作:

1) gcc 16-1.c -o 16-1.out编译正确,打印结果:

12
1    
-1
32      

分析:

        数学运算符优先级高于逻辑运算符。

小贴士

防错准则:

 - 避免位运算符逻辑运算符数学运算符同时出现在一个表达式中

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

小技巧:

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

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

编程实验
交换两个整型变量的值
16-2.c

#include <stdio.h>		//只从IDE中找头文件

/*
借助一个变量为中间值,进行两个数值交换
*/
#define SWAP1(a,b)   \
{		             \
    int t = 0;	     \
    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 argc , char* argv[])
{
    int a = 1;
    int b = 2;

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

    //SWAP1(a , b);
    //SWAP2(a , b);
    SWAP3(a , b);
    /*
    SWAP3:
    第一行结果:a = (00 00 00 01)^(00 00 00 10) = 11(3)
    第二行结果:b = (00 00 00 11)^(00 00 00 10) = 01(a:1)
    第三行结果:a = (00 00 00 11)^(00 00 00 01) = 10(b:2)
    */
    printf("a = %d\n" , a);
    printf("b = %d\n" , b);
	
    return 0;
}

操作:

1) 使用SWAP1(a, b):gcc 16-2.c -o 16-2.out编译正确,打印结果:

a = 1
b = 2    
a = 2    
b = 1    

分析:

        数值交换,用变量太普通了。

2) 使用SWAP2(a, b):gcc 16-2.c -o 16-2.out编译正确,打印结果:

a = 1
b = 2    
a = 2    
b = 1    

分析:

        使用加减法,要考虑数值类型溢出问题,如果想加时,两个数值过大,相加可能超过数据类型最大范围。

3) 使用SWAP3(a, b):gcc 16-2.c -o 16-2.out编译正确,打印结果:

a = 1
b = 2    
a = 2    
b = 1 

分析:

        使用异或没有数值类型溢出现象。

三、位运算与逻辑运算

1)位运算逻辑运算不同:

 - 位运算没有短路规则,每个操作数都参与运算

 - 位运算的结果为整数,而不是0或1

 - 位运算优先级高于逻辑运算优先级

实例分析
混淆概念的判断条件
16-3.c

#include <stdio.h>

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

操作:

1) gcc 16-3.c -o 16-3.out编译问题,打印结果:

Run here...

分析:

        位运算没有短路原则,前置++都是计算后才返回数值。

小结

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

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

3.位运算没有短路规则,所有操作数均会求值

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

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

发布了40 篇原创文章 · 获赞 1 · 访问量 1766

猜你喜欢

转载自blog.csdn.net/piaoguo60/article/details/103865411
今日推荐