C语言——位运算

本篇截图内容(除负数的补码运算以外)全部摘自谭浩强老师的《C程序设计(第五版)学习辅导》一书中的第12章。

 

  位运算是C语言的重要特点,是其他计算机高级语言所没有的。所谓位运算是指以二进制位为对象的运算。在系统软件中,常要处理二进制位的问题。例如,将一个存储单元中的各二进制位左移或右移一位、两个数按位相加等。

1.1位运算和位运算符

注意:参加位运算的对象只能是整型或字符型的数据,不能为实型数据

1.1.1按位“与”

特殊用途:

(要想将哪一位保留下来,就与一个数进行&运算,此数在该位取1)

1.1.2按位“或”

特殊用途:

常用来对一个数据的某些位定值为1。例如,a是一个整数,有表达式:a|0377,则低8位全置为1,高8位保留原样。

1.1.3按位“异或”

特殊用途:

1.1.4按位“取反”

特殊用途:

注:~运算符的优先级比算术运算符、关系运算符、逻辑运算符和其他位运算符都高。例如:~a&b,先进行~a运算,再进行&运算

1.1.5左移

特殊用途:

左移1位相当于该数乘以2,左移2位相当于该数乘以2*2。但此结论只适用于该数左移时被溢出舍弃的高位中不包含1的情况。由下表可以看出,64在左移1位后相当于乘2,左移2位后,值就等于0了。

1.1.6右移

注:右移时,对于无符号数左边高位补0对于有符号数,若原来符号位为0(该数为正),则左边也补0若符号位原来为1(即负数),则高位补0还是1,要取决于所用的计算机系统,有的系统补0,有的系统补1。补0的称为“逻辑右移”,即不考虑数的符号问题,补1的称为“算数右移”,即保持原有的符号。

特殊用途:

右移1位相当于除以2,右移n位相当于除以2的n次方。

1.1.7位运算赋值运算符

1.1.8不同长度的数据进行位运算

1.2位运算举例

  • 从一个整数a中把从右端开始的4~7位取出来。

【思路】

【代码实现】

#include<stdio.h>

int main()
{
	void print_bin1(int);
	unsigned a,b,c,d;
	printf("please enter a:");
	scanf("%o",&a);
	b=a>>4;
	c=~(~0<<4);
	d=b&c;
	printf("%o,%d\n%o,%d\n\n",a,a,d,d);
	print_bin1(a);
	printf("\n");
	print_bin1(d);

	return 0;
}

//输出二进制——位运算法
void print_bin1(int numb)
{
    char *buff = (char*)malloc(32*sizeof(char));
    int count = 0;
	int index = 0;
    count = 0;
    do{
        buff[count++] = numb&1;
        numb = numb >> 1;
        if(numb == 0){
            break;
        }
        index ++;
    }while(index < 32);
    for(count--;count >= 0; count--){
        printf("%d",buff[count]);
    }
	printf("\n");
    free(buff);
}
  • 循环移位。假设用两个字节存放一个短整型(short int型),将a右移循环移n位,即将左面16-n位右移n位,原来右端n位移到最左面n位。

【思路】

【代码实现】

注意:以下实现方法并非实际意义上的循环移动,int是32位,则八进制157653的二进制0000 0000 0000 0000 1101 1111 1010 1011左移时,是前面的0换到右边了,并不是110换到右边

#include<stdio.h>

int main()
{
	void print_bin1(unsigned int numb);
	unsigned int a,b,c;		//默认是unsigned int(32位)
	int n;

	a=0157653;
	n=3;

	printf("循环右移->\n");
	b=a<<(32-n);
	c=a>>n;
	c=c|b;
	printf("\na:%o\nc:%o\n\n",a,c);

	printf("循环左移->\n");
	a=0157653;
	b=a>>(32-n);
	c=a<<n;
	c=c|b;
	printf("\na:%o\nc:%o\n\n",a,c);

	return 0;
}

实际意义上的循环移动代码实现如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>

int main()
{
	void print_bin1(int numb);
	unsigned int a,b,c;		//默认是unsigned int(32位)
	int n,count;	//count为n的二进制位数(不包括前面的0)
	char str[32];

	a=0157653;		//八进制
	n=3;	//移动的位数
	itoa(a,str,2);
	count=strlen(str);

	printf("循环右移->\n");
	b=(a<<(count-n))&(int)(pow(2.0,count)-1);
	c=a>>n;
	c=c|b;
	printf("\na:%o\nc:%o\n\n",a,c);

	printf("循环左移->\n");
	a=0157653;		//八进制
	b=a>>(count-n);
	c=(a<<n)&(int)(pow(2.0,count)-1);
	c=c|b;
	printf("\na:%o\nc:%o\n\n",a,c);

	return 0;
}

1.3位段

    对内存中信息的存取一般是以字节为单位。实际上,有时存储一个信息不必用一个或多个字节,例如,“真”或“假”用0或1表示,只需1个二进制位即可。在计算机用于过程控制、参数检测或数据通信领域时,控制信息往往只占1个字节中的1个或几个二进制位,常常在一个字节中放几个信息。

但是,以上方法太麻烦,故可以使用以下的位段结构体的方法。

C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这种以位为单位的成员称为“位段”或“位域(bit field)”。利用位段能够用较少的位数存储数据。

【注:】

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值