- 内容提要
- 前言
- 第 1 章 预备知识
- 第 2 章 开始学习 C++
- 第 3 章 处理数据
- 第 4 章 复合类型
- 第 5 章 循环和关系表达式
- 第 6 章 分支语句和逻辑运算符
- 第 7 章 函数——C++的编程模块
- 第 8 章 函数探幽
- 第 9 章 内存模型和名称空间
- 第 10 章 对象和类
- 第 11 章 使用类
- 第 12 章 类和动态内存分配
- 第 13 章 类继承
- 第 14 章 C++中的代码重用
- 第 15 章 友元、异常和其他
- 第 16 章 string 类和标准模板库
- 第 17 章 输入、输出和文件
- 第 18 章 探讨 C++新标准
- 附录 A 计数系统
- 附录 B C++保留字
- 附录 C ASCII 字符集
- 附录 D 运算符优先级
- 附录 E 其他运算符
- 附录 F 模板类 string
- 附录 G 标准模板库方法和函数
- 附录 H 精选读物和网上资源
- 附录 I 转换为 ISO 标准 C++
- 附录 J 复习题答案
E.1 按位运算符
按位运算符对整数值的位进行操作。例如,左移运算符将位向左移,按位非运算符将所有的 1 变成 0,所有的 0 变成 1,C++共有 6 个这样的运算符:<<、>>、~、&、|和^。
E.1.1 移位运算符
左移运算符的语法如下:
其中,value 是要被操作的整数值,shift 是要移动的位数。例如,下面的代码将值 13 的所有位都向左移 3 位:
腾出的位置用 0 填充,超出边界的位被丢弃(参见图 E.1)。
由于每个位都表示右边一位的 2 倍(参见附录 A),所以左移一位相当于乘以 2。同样,左移 2 位相当于乘以 22,左移 n 位相当于乘以 2n。因此,13<<3 的值为 13 × 23,即 104。
图 E.1 左移运算符
左移运算符提供了通常可以在汇编语言中找到的功能。不过,左移运算符在汇编语言中会直接修改寄存器的内容,而 C++左移运算符生成一个新值,而不修改原来的值。例如,请看下面的代码:
上述代码不会修改 x 的值。表达式 x<<3 使用 x 的值来生成一个新值,就像 x+3 会生成一个新值,而不会修改 x 一样。
如果要用左移运算符来修改变量的值,则还必须使用赋值运算符。可以使用常规的赋值运算符或<<=运算符(该运算符将移动与赋值结合在一起):
正如所期望的,右移运算符(>>)将位向右移,其语法如下:
其中,value 是要移动的整数值,shift 是要移动的位数。例如,下面的代码将值 17 中所有的位向右移两位:
对于无符号整数,腾出的位置用 0 填充,超过边界的位被删除。对于有符号整数,腾出的位置可能用 0 填充,也可能用原来最左边的位填充,这取决于 C++实现(图 E.2 是一个用 0 填充的例子)。
图 E.2 右移运算符
向右移动一位相当于除以 2。向右移动 n 位相当于除以 2n。
C++还定义了一个“右移并赋值”运算符,如果要用移动后的值替换变量的值,可以这样做:
在有些系统上,使用左移运算符(右移运算符)实现将整数乘(除)以 2 的速度比使用乘(除)法运算符更快,但由于编译器在优化代码方面越来越好,因此这种差异正在减小。
E.1.2 逻辑按位运算符
逻辑按位运算符类似于常规的逻辑运算符,只是它们用于值的每一位,而不是整个值。例如,请看常规的非运算符(!)和位非(或求反)运算符(~)。!运算符将 true(或非零值)转换为 false,将 false 值转换为 true。~运算符将每一位转换为它的反面(1 转换为 0,0 转换为 1)。例如,对于 unsigned char 值 3:
表达式!x 的值为 0。要知道~x 的值,先把它写成二进制形式:00000011。然后将每个 0 转换为 1,将每个 1 转换为 0。这样将得到值 11111100,在十进制中,为 252(图 E.3 是一个 16 位的例子)。新值是原值的补值。
按位运算符 OR(|)对两个整数值进行操作,生成一个新的整数值。如果被操作的两个值的对应位至少有一个为 1,则新值中相应位为 1,否则为 0(参见图 E.4)。
图 E.3 按位非运算符
图 E.4 按位运算符 OR
表 E.1 对∣运算符的操作方式进行了总结。
表 E.1 b1|b2 的值
位 值 | b1 = 0 | b1 = 1 |
---|---|---|
b2 = 0 | 0 | 1 |
b2 = 1 | 1 | 1 |
运算符| =组合了按位运算符 OR 与赋值运算符的功能:
按位运算符 XOR(^)将两个整数值结合起来,生成一个新的整数值。如果原始值中对应的位有一个(而不是两个)为 1,则新值中相应位为 1;如果对应的位都为 0 或 1,则新值中相应位为 0(参见图 E.5)。
图 E.5 按位运算符 XOR
表 E.2 总结了^运算符的结合方式。
表 E.2 b1^b2 的值
位 值 | b1 = 0 | b1 = 1 |
---|---|---|
b2 = 0 | 0 | 1 |
b2 = 1 | 1 | 0 |
^ =运算符结合了按位运算符 XOR 和赋值运算符的功能:
按位运算符 AND(&)将两个整数结合起来,生成一个新的整数值。如果原始值中对应位都为 1,则新值中相应位为 1,否则为 0(参见图 E.6)。
图 E.6 按位运算符 AND
表 E.3 总结了&运算符是如何运算的。
表 E.3 b1&b2 的值
位 值 | b1 = 0 | b2 = 1 |
---|---|---|
b2 = 0 | 0 | 0 |
b2 = 1 | 0 | 1 |
& =运算符结合了按位运算符 AND 和赋值运算符的功能:
E.1.3 按位运算符的替代表示
对于几种按位运算符,C++提供了替代表示,如表 E.4 所示。它们适用于字符集中不包含传统按位运算符的区域。
表 E.4 按位运算符的替代表示
标 准 表 示 | 替 代 表 示 |
---|---|
& | bitand |
& = | and_eq |
| | bitor |
|= | or_eq |
~ | compl |
^ | xor |
^ = | xor_eq |
这些替代表示让您能够编写下面这样的语句:
E.1.4 几种常用的按位运算符技术
控制硬件时,常涉及打开/关闭特定的位或查看它们的状态。按位运算符提供了执行这种操作的途径。下面简要地介绍一下这些方法。
在下面的示例中,lottabits 表示一个值,bit 表示特定位的值。位从右到左进行编号,从 0 开始,因此,第 n 位的值为 2n。例如,只有第 3 位为 1 的整数的值为 23(8)。一般来说,正如附录 A 介绍的,各个位都对应于 2 的幂。因此我们使用术语位(bit)表示 2 的幂;这对应于特定位为 1,其他所有位都为 0 的情况。
1.打开位
下面两项操作打开 lottabits 中对应于 bit 表示的位:
它们都将对应的位设置为 1,而不管这一位以前的值是多少。这是因为对 1 和 1 或者 0 和 1 执行 OR 操作时,都将得到 1。lottabits 中其他所有位都保持不变,这是因为对 0 和 0 做 OR 操作将得到 0,对 1 和 0 做 OR 操作将生成 1。
2.切换位
下面两项操作切换 lottabits 中对应于 bit 表示的位。也就是说,如果位是关闭的,则将被打开;如果位是打开的,将被关闭:
对 0 和 1 执行 XOR 操作的结果为 1,因此将关闭已打开的位;对 1 和 1 执行 XOR 操作的结果为 0,因此将打开已关闭的位。lottabits 中其他所有位都保持不变,这是因为对 0 和 0 执行 XOR 操作的结果为 0,对 1 和 0 执行 XOR 操作的结果为 1。
3.关闭位
下面的操作将关闭 lottabits 中对应于 bit 表示的位:
该语句关闭相应的位,而不管它以前的状态如何。首先,运算符~bit 将原来为 1 的位设置为 0,原来为 0 的位设置为 1。对 0 和任意值执行 AND 操作都将得到 0,因此关闭相应的位。lottabits 中其他所有位都保持不变,这是因为对 1 和任意值执行 AND 操作时,该位的值将保持不变。
下面是一种更简洁的方法:
4.测试位的值
如果要确定 lottabits 中对应于 bit 的位是否为 1,则下面的测试不一定管用:
这是因为即使 lottabits 中对应的位为 1,而其他位也可能为 1。仅当对应的位为 1,而其他位皆为 0 时,上述等式才为 true。因此修补的方式是,首先对 lottabits 和 bit 执行 AND 操作,这样生成的值的对应位保持不变,因为对 1 和任何值执行 AND 操作都将保持该值不变;而其他位都为 0,因为对 0 和任何值执行 AND 操作的结果都为 0。正确的测试如下:
实际应用中,程序员常将上述测试简化为:
因为 bit 中有一位为 1,而其他位都为 0,因此 lottabits & bit 的结果要么为 0(测试结果为 false),要么为 bit(非零值,测试结果为 true)。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论