C Primer Plus (第五版)中文版——第 15 章 位操作

15.1  二进制数、位和字节

以2为基数表示的数字称为二进制数(binary number)。二进制使用2的幂,使用的数字是0和1。

15.1.1  二进制整数

一个字节(byte)通常包括8个位(bit)。在字节中,位7称为高位(high-order bit),为0称为低位(low-order bit)。一个字节可以存储的数的范围是0~255,总共256(2^8)个可能的值。改变对位模式的解释方式,一个字节可以存储从-128~+127之间的整数,总共256(2^8)个可能的值。

15.1.2  有符号整数

有符号数的表示方法是由硬件决定的,而不是由 C 决定。通常保留高位来表示数的符号。

15.1.3  二进制浮点数

浮点数分两部分存储:一个二进制小数和一个二进制指数。

一、二进制小数

在二进制小数中,使用2的幂作为分母。实际上,二进制计数法只能精确地表示多个1/2的幂的和,许多小数不能用其精确表示。

二、浮点数表示法

要在计算机中表示一个浮点数,需要留出若干个位存放一个二进制小数,其他为存放一个指数。

15.2  其他基数

15.2.1  八进制

八进制(octal):以8为基数的数制系统。该系统使用8的幂,使用的数字是0~7。1个八进制位对应于3个二进制位。

15.2.2  十六进制

十六进制(hexadecimal):以16为基数的数制系统。该系统使用16的幂,使用的数字(字符)是0~F。1个十六进制位对应于4个二进制位。

15.3  C 的位运算符

C 提供位的逻辑运算符和移位运算符。

15.3.1  位逻辑运算符

位逻辑运算符
二进制反码或按位取反 ~ 将每个1变为0,将每个0变为1
位与(AND) & 对两个操作数逐位进行与运算
位或(OR) | 对两个操作数逐位进行或运算
位异或(相同为0,不同为1) ^ 对两个操作数逐位进行异或运算
位逻辑运算符用法:MASK=00000010(MASK只有位1是非零)
掩码 flags = flags & MASK;

将 flags 的除位1之外的所有位都被设为0,称为“使用掩码”

打开位 flags = flags | MASK; 将 flags 的位1设为1,其他位保持不变
关闭位 flags = flags & ~MASK; 将 flags 的位1设为0,其他位保持不变
转置位 flags = flags ^ MASK; 将 flags 的位1转置,其他位保持不变
查看一位的值 if((flags & MASK) == MASK) flags 的位1是否为1。若是则判断语句为真

15.3.7  移位运算符

一、左移:<<

  • 左移运算符 << 将其左侧操作数的值每位向左移动,移动的位数由其右侧操作数指定。
  • 丢弃移出左侧操作数末端的位,右侧空出的位用0填充。10001010 << 2 == 00101000
  • 移位操作产生一个新位值,但不改变其操作数。可以使用左移赋值运算符 <<= 来实际改变一个变量的值。

二、右移:>>

  • 右移运算符 >> 将其左侧操作数的值每位向右移动,移动的位数由其右侧操作数指定。
  • 丢弃移出右侧操作数末端的位,左侧空出的位用0填充。对无符号值,10001010 >> 2 == 00100010
  • 移位操作产生一个新位值,但不改变其操作数。可以使用右移赋值运算符 >>= 来实际改变一个变量的值。

三、用法

移位运算能够提供便捷、高效的对2的幂的乘法和除法:

number << n number 乘以2的n次幂
number >> n 如果 number 非负,则用 number 除以2的n次幂

15.4  位字段

位字段是一个 unsigned int 或 signed int 中一组相邻的位。位字段由一个结构声明建立,该结构声明为每一个字段提供标签,并决定字段的长度。例如,以下声明建立了3个1位字段和1个5位字段:

struct {
        unsigned int autfd: 1;
        unsigned int bldfc: 1;
        unsigned int undln: 1;
        unsigned int itals: 5;
} prnt;

该定义使 prnt 包含4个1位字段,现在可以使用普通的结构成员运算符将值赋给单独的字段(必须确保值没有超出字段的容量):

prnt.itals = 18;
prnt.undln = 1;

变量 prnt 被存储在一个 int 大小的存储单元中,不允许一个字段跨越两个 unsigned int 之间的边界。如果声明的总位数超过一个 unsigned int 大小,编译器自动地移位一个这样的字段定义,使字段按 unsigned int 边界对齐,这时第一个 unsigned int 中会留下一个未命名的洞。

可以使用未命名的字段宽度“填充”未命名的洞。使用一个宽度为零的未命名的字段迫使下一个字段与下一个整数对齐:

struct {
        unsigned int filed1: 1;
        unsigned int       : 2;        //前一个字段和后一个字段之间有一个2位的间隙
        unsigned int filed2: 1;
        unsigned int       : 0;        //使后一个字段在另一个int中存储
        unsigned int filed3: 1;
} stuff;

你可能感兴趣的:(C语言,C,Primer,Plus)