第7章用户定制数据类型7.1.5位运算•掌握位运算的概念和方法,学会使用位运算符;•学会通过位运算实现对某些位的操作;•了解位段的概念以及位段的定义和引用。7.1.5位运算一、相关概念1.位(bit):是指二进制中的位,它是计算机能处理的最小单位。2.字节(byte):是计算机处理的基本单位。计算机的内存是按字节进行分配的。一个字节有八位二进制数组成。所以我们在C语言中数据类型都是以字节为基本单元。计算机系统的内存储器,是由许多称为字节的单元组成的,1个字节由8个二进制位(bit)构成,每位的取值为0/1。最右端的那1位称为“最低位”,编号为0;最左端的那1位称为“最高位”,而且从最低位到最高位顺序,依次编号。765432103.补码:一个正数的补码是其本身;一个负数的补码是其绝对值按位取反后加1。计算机是以补码的形式存放数的。例如:-7的补码是1111111111111001位运算和位运算符一、位运算的概念位运算:以二进制位为单位的运算。二、位运算符“位运算”仅限于整数(整型数和字符型)。位逻辑运算符(~、&、^(异或)、|)位移位运算符(、)位复合赋值运算符(&=、|=、^=、=、=)1.按位与──&(1)格式:x&y(2)规则:对应位均为1时才为1,否则为0:3&9=1。例如,3&9=1:0011&1001────0001=1(3)主要用途:取(或保留)1个数的某(些)位,其余各位置0。2.按位或──|(1)格式:x|y(2)规则:对应位均为0时才为0,否则为1:3|9=11。例如,3|9=11:0011|1001────1011=11(3)主要用途:将1个数的某(些)位置1,其余各位不变。3.按位异或──^(1)格式:x^y(2)规则:对应位相同时为0,不同时为1:3^9=10。(3)主要用途:使1个数的某(些)位翻转(即原来为1的位变为0,为0的变为1),其余各位不变。例:交换两个变量的值,不用临时变量x=x^y;y=x^y;x=x^y;4.按位取反──~(1)格式:~x(2)规则:各位翻转,即原来为1的位变成0,原来为0的位变成1:在16位机中,~0=0xffff,~9=0xfff6。(3)主要用途:间接地构造一个数,以增强程序的可移植性。5.按位左移──(1)格式:x位数(2)规则:使操作数的各位左移,低位补0,高位溢出:52=20。(3)左移1位,相当于乘26.按位右移──(1)格式:x位数(2)规则:使操作数的各位右移,移出的低位舍弃;高位:1)对无符号数和有符号中的正数,补0;2)有符号数中的负数,取决于所使用的系统:补0的称为“逻辑右移”,补1的称为“算术右移”。例如,202=5。应用举例[例1]从键盘上输入1个正整数给int变量num,输出由8~11位构成的数(从低位、0号开始编号)。基本思路:(1)使变量num右移8位,将8~11位移到低4位上。(2)构造1个低4位为1、其余各位为0的整数。(3)与num进行按位与运算。/*程序功能:输出一个整数中由8~11位构成的数*/main(){intnum,mask;printf(Inputaintegernumber:);scanf(%d,&num);num=8;/*右移8位,将8~11位移到低4位上*/mask=~(~04);/*间接构造1个低4位为1、其余各位为0的整数*/printf(result=0x%x\n,num&mask);}程序运行情况:Inputaintegernumber:1000←┘result=0x3[例2]从键盘上输入1个正整数给int变量num,按二进制位输出该数。#includestdio.hmain(){intnum,mask,i;printf(Inputaintegernumber:);scanf(%d,&num);mask=115;/*构造1个最高位为1、其余各位为0的整数(屏蔽字)*/printf(%d=,num);for(i=1;i=16;i++){putchar(num&mask?’1’:‘0’);/*输出最高位的值(1/0)*/num=1;/*将次高位移到最高位上*/if(i%4==0)putchar(‘,’);/*四位一组,用逗号分开*/}printf(\bB\n);}程序运行情况:Inputaintegernumber:1000←┘1000=0000,0011,1110,1000B三、位运算符的优先级位运算符自身的优先级为(从高到低):~、(、)、&、^、|位运算符与其他运算符相比较优先级为(从高到低):~、算术运算符、(、)、关系运算符、&、^、|、逻辑运算符、条件运算符、赋值(复合赋值)运算符、逗号运算符例如:chara=9,b=020;printf(“%o\n”,~a&b1);输出结果:40§7.1.5位段位段:在一个结构体中可以以位为单位来指定其成员所占内存长度,这种以位为单位的成员称为位段(或位域)。如:structpacked_data{unsignedinta:2;unsignedintb:3;unsignedintc:4;inti;}data;存储单元分配:共4个字节716432abci位段的引用:结构体变量名.位段成员名如:structpacked_data{unsigneda:2;unsignedb:3;unsignedc:4;inti;}data;位段的引用如下:data.a=2;data.b=7;data.c=9;注意:位段允许的最大值范围。data.a=9;╳说明:⑴位段成员的类型必须指定为unsignedint类型。⑵允许在位段中定义无名字段,其含义为跳过该字节剩余的位或指定的位不用。当无名字长度为0时,跳过该字节剩余的位不用;当无名字段长度为n时,跳过n位不用。如:structpacked_data{unsigneda:2;unsignedb:3;unsigned:0;unsignedc:4;inti;}data;存储单元分配:共4个字节4343216abci又如:structpacked_data{unsigneda:2;unsignedb:3;unsigned:2;unsignedc:4;inti;}data;存储单元分配:共4个字节5216432abci⑶位段的长度不能大于存储单元的长度。即≤16位⑷不能引用位段地址。(5)段可以在数值表达式中引用,也可以用整型格式输出。•在一个结构体中可以混合使用位段和通常的结构体成员。•例7.6structdata{inti;/*非位段*/unsignedinta:3;/*位段*/unsignedintb:5;/*位段*/unsignedintc:2;/*位段*/floatf;/*非位段*/};•第一个成员是整型的,占2个字节,下面三个位段a,b,c,占2个字节(多余6位),最后f又占4个字节。共占8个字节。练习题1.以下正确的描述是。A、对共用体初始化时,只能对第一个成员进行初始化,每一瞬时起作用的成员是最后一次为其赋值的成员B、结构体可以比较,但不能将结构体类型作为函数返回值类型C、函数定义可以嵌套D、关键字typedef用于定义一种新的数据类型2.设有如下定义:structst{inta;floatb;}st1,*pst;若有pst=&st1;则下面引用正确的是________。A)(*pst.st1.b)B)(*pst).bC)pst-st1.bD)pst.st1.b3.已知学生记录描述为:structstudent{intno;charname[20];charsex;struct{intyear;charmonth[20];intday;}birth;};structstudents;设变量s中的“生日”应是“1984年11月11日”,下列对“生日”的正确赋值方式是A)s.birth.year=1984;s.birth.month=11;s.birth.day=11;B)s.birth.year=1984;s.birth.month=11;s.birth.day=11;C)s.birth.year=1984;strcpy(s.birth.month,11);s.birth.day=11;D)s.birth.year=1984;s.birth.month[]={11};s.birth.day=11;4.#includestdio.hstructname{charfirst[20];charlast[20];};structbeam{intlimbs;structnametitle;charty[30];};main(){structbeam*pb;structbeamdeb={6,{Berbnazel,Gwolkapwolk},Arcturan};pb=&deb;printf(%d\n,deb.limbs);printf(%s\n,pb-ty);printf(%s\n,pb-ty+2);}运行结果是:改错.1#defineNLIST1000typedefstructcblock{structcblock*cnext;charinfo[6];}BLOCK;BLOCKcfree[NLIST];voidshow(){BLOCK*cfreelist=cfree;BLOCKp=&cfreelist[NLIST];while(cfreelistp){printf(“%s\n”,cfreelist.info);cfreelist++;}}*pCfreelist-改错.#defineNLIST=1000;typedefstructcblock{cblock*cnext;charinfo[6];}BLOCK;BLOCKcfree[NLIST];BLOCK*cfreelist=cfree;cinit(){BLOCK*cpp;for(cpp=cfree;cpp=&cfree[NLIST];cpp++){cpp-cnext=cfreelist;cfreelist=cpp;}}不要等号Structcblock改错.typedefstructnode{structnode*n[2];charcolor[10]}NODE;typedefNODE*NODE_REF;typedefunionexnode{NODEnd;unionexnode*link;}EXTNODE;staticEXTNODE*next_avail;少分号改错.structstacknode{intdata;structstacknode*next;};typedefstructstacknodeSTACKNODE;typedefSTACKNODE*STACKNODEPTR;voidpush(STACKNODEPTR*tp,intinfor){STACKNODEPTRnp=(STACKNODEPTR)malloc(4);if(np){np.data=info;np.next=tp;*tp=np;}}4改为sizeof(STACKNODE)np-np-next=*tp;structemploy*delete(structemployee*head,intnum){structemployee*p1,*p2;if(head==NULL){printf(\nlistnull);retutnhead;}p1=①__________;while(②_______________________){p2=p1;p1=③____________;}if(num==p1-num){if(④______________)head=p1-next;else⑤_____________________;printf(\ndeleted);}elseprintf(%dnotfound\n,num);returnhead;}①head;②num!=p1-num&&p1-next!=NULL③p1