——位运算)

Posted 二木成林

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了——位运算)相关的知识,希望对你有一定的参考价值。

12.1 位运算符

C语言提供了六种位运算符:

  • &:按位与
  • |:按位或
  • ^:按位异或
  • ~:取反
  • <<:左移
  • >>:右移

12.1.1 按位与运算

按位与运算符"&"是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进制位均为1时,结果位才为1,否则为0。参与运算的数以补码方式出现。如9&5

 0000 10019的二进制补码)
&0000 01015的二进制补码)
=0000 00011的二进制补码)     

按位与运算通常用来对某些位清0或保留某些位。

#include <stdio.h>

int main() 
    int a = 9, b = 5, c;
    c = a & b;
    printf("%d&%d=%d", a, b, c);

12.1.2 按位或运算

按位或运算符“|”是双目运算符。其功能是参与运算的两数各对应的二进位相或。只要对应的两个二进制位有一个为1时,结果位就为1。参与运算的两个数均以补码出现。如9|5

 0000 10019的二进制补码)
|0000 01015的二进制补码)
=0000 110113的二进制补码)  

即:

#include <stdio.h>

int main() 
    int a = 9, b = 5, c;
    c = a | b;
    printf("%d|%d=%d", a, b, c);// 9|5=13

12.1.3 按位异或运算

按位异或运算符“^”是双目运算符。其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异(即两位二进制中一位是0,另外一位是1的情况)时,结果为1。参与运算数仍以补码出现。如9^5

 0000 10019的二进制补码)
^0000 01015的二进制补码)
=0000 110012的二进制补码)  

即:

#include <stdio.h>

int main() 
    int a = 9, b = 5, c;
    c = a ^ b;
    printf("%d^%d=%d", a, b, c);// 9^5=12

12.1.4 求反运算

求反运算符为单目运算符,具有右结合性。其功能是对参与运算的数的各二进制位按位求反。如~9

~0000 10019的二进制补码)
=1111 0110    

即:

#include <stdio.h>

int main() 
    int a = 9, b;
    b = ~a;
    printf("~%d=%d", a, b);// ~9=-10

12.1.5 左移运算

左移运算符“<<”是双目运算符。其功能把“<< ”左边的运算数的各二进制位全部左移若干位,由“<<”右边的数指定移动的位数,高位丢弃,低位补0。如:

a=3;3的二进制位为0000 0011)
a<<4=0011 0000

即:

#include <stdio.h>

int main() 
    int a = 3, b;
    b = a << 4;
    printf("%d<<4=%d", a, b);// 3<<4=48

12.1.6 右移运算符

右移运算符“>>”是双目运算符。其功能是把“>>”左边的运算数的各二进制位全部右移若干位,“>>”右边的数指定移动的位数。应该说明的是,对于有符号数,在右移时,符号位将随同移动。当为正数时,最高位补0,而为负数时,符号位为1,最高位是补0或是补1 取决于编译系统的规定。如:

a=15;15的二进制是0000 1111)
a>>2=0000 0011    

即:

#include <stdio.h>

int main() 
    unsigned int a = 15, b;
    b = a >> 2;
    printf("%d>>2=%d", a, b);// 15>>2=3

12.2 位域(位段)

有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。

所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。

即可以在一个字节中的不同位中存储不同的信息,把空间充分利用起来。

12.2.1 位域的定义和位域变量的声明

位域的定义语法如下:

struct 位域结构名 
  类型说明符 位域名: 位域长度;
  ...
;

例如:

struct bs 
    int a:8;
    int b:2;
    int c:6;
;

位域变量的声明:与结构变量说明的方式相同。 可采用先定义后说明,同时定义说明或者直接说明这三种方式。如:

// 说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位
struct bs 
    int a:8;
    int b:2;
    int c:6;
 data;

关于位域的定义的注意事项:

  • 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。
// 在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位
struct bs 
       unsigned a:4
       unsigned :0        /*空域*/
       unsigned b:4       /*从下一单元开始存放*/
       unsigned c:4
;
  • 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进制。
  • 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。位域在本质上就是一种结构类型,不过其成员是按二进位分配的。
struct k 
      int a:1
      int  :2          /*该2位不能使用*/
      int b:3
      int c:2
;

12.2.2 位域的使用

位域的使用和结构成员的使用相同,其一般形式为:

位域变量名·位域名

位域允许用各种格式输出。

#include <stdio.h>

struct bs 
    unsigned a: 1;
    unsigned b: 3;
    unsigned c: 4;
 bit, *pbit;

int main() 
    bit.a = 1;// 二进制位是0000 0001,只需要1位二进制就能保存
    bit.b = 7;// 二进制位是0000 0111,只需要3位二进制就能保存
    bit.c = 15;
    printf("%d,%d,%d\\n", bit.a, bit.b, bit.c);// 1,7,15
    pbit = &bit;
    pbit->a = 0;
    pbit->b &= 3;
    pbit->c |= 1;
    printf("%d,%d,%d\\n", pbit->a, pbit->b, pbit->c);// 0,3,15

以上是关于——位运算)的主要内容,如果未能解决你的问题,请参考以下文章

位运算符-异或^

算法模板-----位运算

Java 运算符,条件结构小总结

C程序设计之位运算

位运算符,原码反码补码

JAVA位赋值条件运算符等