程序员经常把许多独特但具有相关含义的操作数打包放在一个存储单元中。
比如:日期和时间的表示,将其打包成一个32位的字。 31 25 24 21 20 16 15 11 10 5 4 0 小型嵌入式系统也会打包数据,以减少可读写内存的数量。 如:当某个嵌入式应用程序需要一个布尔值数组时,它就有可能把8个1位的布尔变量打包进每个字节中,而不是使用整个字节来保存一个只能为0或1的值。 BYTE8 flags[8]; 位运算和布尔运算的区别 C语言提供按位运算符和布尔运算符来对位进行操作。但是两者之间还是有区别的。 布尔运算符用于构成条件表达式(如if 语句中) 按位运算符则用于操纵位 操作 | 布尔运算符 | 按位运算符 | 与 | && | & | 或 | || | | | 异或 | 不支持 | ^ | 非 | ! | ~ |
大多数的C编译器没有提供布尔数据类型。作为替代,布尔运算会产生int类型结果,并分别用1和0来表示真值或假植。任何数值数据类型都可以用作布尔操作数。数值0被解释成假植,任何非0值则解释成真值。 在编译器中有如下的定义: Typedef char BOOL; #define FALSE (0) #define TRUE (!FALSE) 按位运算符会把每个操作数视为一个有序的位向量,并产生向量结果。 布尔运算会把每个多位操作数视为单独一个值,只将它解释成真值或假植。 如: 布尔: (5||!3)&&6 运算过程如下: (true OR (NOT true ))AND true (true OR false) AND true True AND true 1 按位:(5|~3)&6 运算过程如下 (0000 0101 OR ~0000 0011) AND 0000 0110 (0000 0101 OR 1111 1100) AND 0000 0110 1111 1101 AND 0000 0110 0000 0100 4 常用的对位的操作: 测试位:测试单个位的值。 常用的表达方式有: If((bit&64)!=0)//check to see if bit 6 is set 注意这里的64是十进制的 If((bits&0x0040)) //check to see if bit 6 is set If(bits &(1<<6))//这种代码比较简洁 设置、清除和反转位 设置常用的表达式: Bits =bits | (1<<7);//设置第7位 写成如下形式更简洁: Bits |= (1<<7); 清除常用的表达式: Bits &=~(1<<7);//clear bit 7 这里要注意一个数据长度的问题,如果编译器使用16位的int,而操作数是一个32的int,那么右边要强制数据类型转换,写成 bits &=~(1L<<7); 如果不进行强制转换,编译器自动将右边的数据扩展成32位,以便和右边的数据兼容,但是编译器是通过插入0来扩展16-31位的,这样当涉及到16位或更多的位移动是,就会发生错误。如: Printf(“%081x\n”,0xffff ffff L &~(1<<15)); 输出的结果是0000 7FFF,显然这不是我们想要的结果。 Printf(“%081X\n”,0xffff ffff &~(1L<<15));输出的结果是FFFF 7FFF,正确 位的反转 Bits ^=(1<<6);// flips bit 6 提取位 提取位域的方法是:通过右移以删除域右边多余的位,并且与表征码作“与”运算以删除左边多余的位。如:从打包的时间中提取出分钟 Time 15 11 10 5 4 0 Time>>5 15 11 10 6 5 0 (time>>5)&0x3f 15 11 10 6 5 0 Minutes=(time>>5)&0x3f 提取了6位 15 11 10 6 5 0 插入位:
替换位域的值是通过如下方式完成的:现将其全部清零,然后通过左移位将替换值与位域对齐,在执行“或”运算将其置入打包的操作数中。 注意:如果发生了插入的值超过目标位域的宽度时,那么在将该值插入到打包的操作数中之前,最好先将其与表征码做“与”运算。 如:将分钟插入到打包的时间表中
oldtime
15 11 10 5 4 0 Newtime = oldtime & ~(0x3f<<5) 15 11 10 5 4 0 newtime |=(newmins&0x3f)<<5
15 11 10 5 4 0
|