网站设计标语,wordpress文章显示颜色,响应式网站源码,php网站的部署4.8位运算符 位运算符作用于整数类型的运算对象#xff0c;并把运算对象看成是二进制位的集合。位运算符提供检查和设置二进制位的功能#xff0c;如17.2节(第640页)将要介绍的#xff0c;一种名为bitset的标准库类型也可以表示任意大小的二进制位集合,所以位运算符同样能用…4.8位运算符 位运算符作用于整数类型的运算对象并把运算对象看成是二进制位的集合。位运算符提供检查和设置二进制位的功能如17.2节(第640页)将要介绍的一种名为bitset的标准库类型也可以表示任意大小的二进制位集合,所以位运算符同样能用于bitset 类型。 一般来说如果运算对象是“小整型”则它的值会被自动提升(参见4.11.1节第142页)成较大的整数类型。运算对象可以是带符号的也可以是无符号的。如果运算对象是带符号的且它的值为负那么位运算符如何处理运算对象的“符号位”依赖于机器。而且,此时的左移操作可能会改变符号位的值因此是一种未定义的行为。 WARNING:关于符号位如何处理没有明确的规定所以强烈建议仅将位运算符用于处理无符号类型。 移位运算符 之前在处理输入和输出操作时我们已经使用过标准I0库定义的运算符和运算符的重载版本。这两种运算符的内置含义是对其运算对象执行基于二进制位的移动操作首先令左侧运算对象的内容按照右侧运算对象的要求移动指定位数然后将经过移动的(可能还进行了提升)左侧运算对象的拷贝作为求值结果。其中右侧的运算对象一定不能为负而且值必须严格小于结果的位数否则就会产生未定义的行为。二进制位或者向左移()或者向右移()移出边界之外的位就被舍弃掉了: 左移运算符()在右侧插入值为0的二进制位。右移运算符()的行为则依赖于其左侧运算对象的类型:如果该运算对象是无符号类型,在左侧插入值为0的二进制位:如果该运算对象是带符号类型在左侧插入符号位的副本或值为0的二进制位如何选择要视具体环境而定。 位求反运算符 位求反运算符(~)将运算对象逐位求反后生成一个新值将1置为0、将0置为1: char 类型的运算对象首先提升成int类型提升时运算对象原来的位保持不变往高位(high order position)添加0即可。因此在本例中首先将bits 提升成 int 类型增加24个高位0随后将提升后的值逐位求反。 位与、位或、位异或运算符 与()、或(|)、异或(^)运算符在两个运算对象上逐位执行相应的逻辑操作: 对于位与运算符()来说如果两个运算对象的对应位置都是1则运算结果中该位为1否则为0。对于位或运算符(1)来说如果两个运算对象的对应位置至少有一个为1则运算结果中该位为1否则为0。对于位异或运算符(^)来说如果两个运算对象的对应位置有且只有一个为1则运算结果中该位为1否则为0。 WARNING:有一种常见的错误是把位运算符和逻辑运算符搞混了比如位与()和逻辑与()、位或(|)和逻辑或(||)、位求反(~)和逻辑非(!)。 使用位运算符 我们举一个使用位运算符的例子:假设班级中有30个学生老师每周都会对学生进行一次小测验测验的结果只有通过和不通过两种。为了更好地追踪测验的结果我们用一个二进制位代表某个学生在一次测验中是否通过显然全班的测验结果可以用一个无符号整数来表示:
unsigned long quizl0; //我们把这个值当成是位的集合来使用定义 quiz1的类型是 unsigned long,这样,quiz1在任何机器上都将至少拥有 32位;给 quiz1赋一个明确的初始值使得它的每一位在开始时都有统一且固定的值。 教师必须有权设置并检查每一个二进制位。例如我们需要对序号为27的学生对应的位进行设置以表示他通过了测验。为了达到这一目的首先创建一个值该值只有第27位是1其他位都是0然后将这个值与quiz1进行位或运算这样就能强行将 quiz1的第27位设置为1其他位都保持不变。 为了实现本例的目的我们将 quiz1的低阶位赋值为0、下一位赋值为1,以此类推,最后统计 guiz1各个位的情况。 使用左移运算符和一个 unsigned long 类型的整数字面值1就能得到一个表示学生27通过了测验的数值: 1UL 27//生成一个值该值只有第27位为1。 1UL的低阶位上有一个1,除此之外(至少)还有31个值为0的位。之所以使用 unsigned1long 类型是因为 int 类型只能确保占用16位而我们至少需要 27位。上面这条表达式通过在值为1的那个二进制位后面添加0使得它向左移动了27位。 接下来将所得的值与 quiz1进行位或运算。为了同时更新quiz1的值使用一条复合赋值语句:
quiz1 | 1UL 27;//表示学生 27 通过了测验|运算符的工作原理和非常相似它等价于
quizl quiz1|1UL27;//等价于quiz1|1UL 27;假定教师在重新核对测验结果时发现学生27实际上并没有通过测验他必须要把第27位的值置为0。此时我们需要使用一个特殊的整数它的第27位是0、其他所有位都是1。将这个值与 quiz1 进行位与运算就能实现目的了:quiz1 (1UL 27); //学生27没有通过测验 通过将之前的值按位求反得到一个新值除了第27位外都是1只有第27位的值是0。 随后将该值与quiz1进行位与运算所得结果除了第27位外都保持不变。 最后我们试图检查学生 27测验的情况到底怎么样: boolstatusquizl(1UL27);//学生27 是否通过了测验? 我们将 quiz1和一个只有第27位是1的值按位求与如果quiz1的第27位是1计算的结果就是非0(真):否则结果是0。 移位运算符(又叫IO运算符)满足左结合律 尽管很多程序员从未直接用过位运算符但是几乎所有人都用过它们的重载版本来进行IO操作。重载运算符的优先级和结合律都与它的内置版本一样因此即使程序员用不到移位运算符的内置含义也仍然有必要理解其优先级和结合律。 因为移位运算符满足左结合律所以表达式
couthithere endl;的执行过程实际上等同于 ((cout“hi”)“there” ) endl; 在这条语句中运算对象hi和第一个组合在一起,它的结果和第二个组合在一起,接下来的结果再和第三个组合在一起。 移位运算符的优先级不高不低介于中间:比算术运算符的优先级低但比关系运算符、赋值运算符和条件运算符的优先级高。因此在一次使用多个运算符时有必要在适当的地方加上括号使其满足我们的要求。
cout4210;//正确:的优先级更高因此输出求和结果 cout(10 42);//正确:括号使运算对象按照我们的期望组合在一起输出1 cout 10 42;//错误:试图比较 cout 和42! 最后一个cout的含义其实是 (cout 10) 42; 也就是“把数字10写到cout然后将结果(即cout)与42进行比较”。