【《C Primer Plus》读书笔记】第15章:位操作
15.1 二进制数、位和字节
通常使用十进制来书写数字,计算机使用二进制。二进制的数字是0和1的组合,计算机通过关闭和打开的组合表示信息,这样很方便。
二进制数(binary number):以 2 为基底表示的数字。
C 语言用字节表示存储系统字符集所需的大小,所以 C 字节可能是 8 位,9 位,16 位或其他值。通常为 8 位。
15.1.1 二进制整数
C语言用字节表示存储系统字符集需要的大小,通常是8位。描述存储器芯片和数据传输率中的字节是八位字节。
15.1.2 有符号整数
二进制原码的最高位是符号位(正数为0,负数为1),后面的位是整数的绝对值的二进制表示。
正数的二进制反码和原码一样。负数的二进制反码是原码的符号位不变,其余位按位取反(1变0,0变1)。
正数的补码和原码、反码一样。负数的二进制补码是反码+1,计算机通常使用二进制补码存储整数。
二进制补码(two’s-complement):
- 正数的高位为 0:表示正数,低七位表示数值;
- 负数的高位为 1:表示负数,低七位各取反加一表示负值的量。
一个二进制补码的相反数,各位取反加一,因为不是对称的。
15.1.3 二进制浮点数
小数也可以用二进制表示,但是许多分数不能用二进制准确地表示。
计算机多使用IEEE 754标准存储浮点数。
15.2 其他进制数
计算机界多使用八进制和十六进制。因为8和16是2的整数次幂。
15.2.1 八进制
八进制基于8的幂,用0-7表示数字。每个八进制位对应三个二进制位。
15.2.2 十六进制
十六进制基于16的幂,用0-15表示数字,10-15分别用A-F表示(C语言中也可以用小写)。每个十六进制位对应四个二进制位。十六进制适合表示字节值。
C语言可以用位和字节进行一些操作。
15.3 C 按位运算符
C语言提供按位逻辑运算符和移位运算符。按位运算符的数据对象用一般形式表示即可。
15.3.1 按位逻辑运算符
四个按位逻辑运算符都用于整型数据(包括char)。这些操作针对每个位进行,不影响其他位。
-
~是按位取反,把1变为0,0变为1。该运算符不改变原变量的值。
-
&是按位与,当两个相应的位都为1时才为1,否则为0。
-
|是按位或,如果两个相应的位有一个是1,结果就是1。只有都是0时结果才是0。
-
^是按位异或,如果相应的位有一个是1,有一个是0,结果就是1。如果都为1或都为0,结果为0。
15.3.2 用法:掩码
按位与运算符常用于掩码,掩码是设置为1或0的位组合。
把一个数与一个只有一位是1,其余位是0的位进行&运算,则只有这一位不变,其余位被置为0。
flag &= MASK
可以把flag的在MASK中为1的位设置为1,相当于只有MASK为1的位才可见。
15.3.3 用法:打开位(设置位)
如果一个整数与另一个整数进行|运算,则该整数中对应另一个整数位为1的位被设置为1,其余位不变。利用这个原理可以打开位。
flag |= MASK
根据MASK中为1的位,把flag对应的位设置为1,其他位不变。
15.3.4 用法:关闭位(清空位)
如果一个整数与另一个整数进行&运算,则该整数中对应另一个整数位为0的位被设置为0,其余位不变。利用这个原理可以关闭位。
flag &= ~MASK
根据MASK中为1的位,把flag对应的位设置(清空)为0,其他位不变。
15.3.5 用法:切换位
切换一个值中的特定位的开关状态,同时保持其他位不变。
用按位异或可以切换位。
flag ^= MASK
flag中与MASK为1的位相对应的位都被切换了,MASK为0的位相对应的位不变。
15.3.6 用法:检查位的值
比较某一位的值需要覆盖其他位。
if((flag & MASK) == MASK)
puts("Wow!");
15.3.7 移位运算符
移位运算符向左或向右移动位。
<<将左侧运算对象每一位向左移动右侧运算对象指定的位数。移出左端的位的值丢失,用0填充右端位置。左移不改变原变量的值。
>>将左侧运算对象每一位向右移动右侧运算对象指定的位数。移出右端的位的值丢失,对于无符号整数,用0填充左端位置。有符号整数的效果取决于机器,可能用0填充,也可能用符号位填充。右移不改变原变量的值。
移位运算符对2的幂进行快速有效的乘法和除法。
移位运算符可用于从较大单元中提取一些位。
15.4 位字段
位字段是一个int或unsigned int类型变量中的一组相邻的位。位字段通过一个结构声明来建立。该结构声明给每个字段提供标签,并确定该字段的宽度。
用法是在成员名后面用一个冒号,在写上所占位的数量,然后分号结束。
可以用.访问成员,赋值。但是赋值不要超过位的数量能表示的最大值。
初始化位字段结构与初始化普通结构相同。
带有位字段的结构是记录设置的方便途径。
如果总位数超过一个字节,会用下一个字节的位置,一个字段不能跨越两个字节,编译器会自动移动,从而在上一个字节留下洞。可以用未命名的字段宽度填充洞。
字段存储在int的顺序取决于机器,有的是从左向右,有的是从右向左。位字段不易移植。
15.5 对齐特性(C11)
C11的对齐特性比用位填充字节更自然,表示了C语言在处理硬件相关问题上的能力。对齐指如何安排对象在内存中的位置。
_Alignof运算符给出一个类型的对齐要求,在此关键字后的圆括号中写上类型名即可。一般对齐值是2的非负整数次幂。
可以用_Alignas说明符指定一个变量或类型的对齐值。但是不能小于基本对齐值。该说明符是声明的一部分,说明符后面的圆括号包含对齐值或类型。