好, 那么, 接下来呢, 做一个选讲内容。我们再跟大家介绍一下位运算。 说好了是选讲内容, 既然讲都是选讲了, 所以肯定不要求大家去掌握。 那么在今后写程序的过程当中呢, 能用到, 你就来看一眼。 如果用不到, 你可以不理它, 没关系。 什么叫位运算? 所谓位运算就是指, 就是对 内存里面, 每一个字节上的二进制位所进行的运算。 这就是位运算。那么当然我们以前讲到过。 其实呢, 在内存里面 字节是程序对内存进行操控的基本单位。 那么这儿的位运算, 虽然我们说是对二进制位进行的运算, 但实际上 这种运算也是通过对字节为单位的控制来实现的。我们做一个解释。 那么C语言或者C++语言中的位运算符呢包含了这么些。 有与运算,或运算, 异或运算, 取反运算,左移运算, 和右移运算。有这么6种。 其中呢,前三种都, 都是双目运算符 所谓的双目运算符就是有两个操作数参与的。 后三种呢, 都是单目运算符。也就是说, 只有一个操作数参与。我们分别做一个介绍。 先来看与运算。所谓的与运算,其实就是说, 把参与运算的两个数据, 这两个数据肯定是可以表示成二进制的字符串, 对吧,一位一位的。那么它每一位, 它个位 均独立进行“与”运算。那么得到的结果就是 位运算的结果。 我们举一个例子。 当然我们这儿举的例子为了方便我们没有把所有的字节全部都画出来。 比方说对于表达式a=3 & 5, 什么意思呢? 这是3所定的二进制的字符串, 这是5所定的二进制的字符串 那么3与5, 它要做什么呢? 结果就是每一位都做与运算, 每一位都做与运算,每一位都做与运算。 最后得到的整体的结果就是位运算的 结果。 位运算, 3与5, 我们可以看一看做完了之后, 它的运算的结果是0000000, 三十一个零, 加上一个一。 这个值的大小其实就是数字1。 整数1。所以说呢, 3与5的值是1。 这就是与运算的基本含意。那么这个与运算呢, 又叫 ”按位与“。 那么说完了与运算我们再来说一下或运算。 所谓的或运算, 也就是指"按位或" 这个运算是指什么呢?是指参加运算的两个数据 它的每一位, 各位均独立进行"或"运算。 比方说刚才那个例子。 3和5。 3和5的最后一个字节拿出来。 全都拿出来。 写出来是这样的。 当然我们也可以把其它的字节全都写上。也进行或运算。 每一位都进行或运算, 每一位都进行或运算。最后得到的结果是, 00000111。 那这个值数是多少,是7。 所以说3和5进行“按位或"的结果是7。 这是或运算。第三种运算呢,叫做"异或"运算。 按位异或运算。它的表示符号呢是向上的箭头。 在我们的键盘上有这个符号。 它所表示的含意呢,就是参加运算的两个数,各位均独立进行异或运算。 什么叫异或运算?我们以前也提到过。所谓异或运算就是参与 运算这两个数,如果是一样的,那么结果就是零。 那么你看,如果要是一样的,结果就是零。 如果参与运算的这两个数是不一样的,是相异的, 结果就是1。 这就是异或运算的基本含意。 那么我们来看一个例子。比方说有两个数,第一个数是这个数, 00111001。第二个数是00101010。 这两个数进行 异按位异或运算,那么得到的结果就是这个数。 那么这个数呢,换算成八进制结果是071. 这个数换算成八进制结果是052。是零开头的。所以 071 按位异或052 所得到的结果,就是这个结果。这个结果其实是对八进制的 023。这就是按位异或的含意。 再往后看, 取反,这是波浪键。那么这也是我们键盘上的一个符号。这是一个单目运算符。它用来表示什么呢? 对一个二进制数进行按位取反。所谓按位取反就是原来是 零的全部变1,原来是1的全部变0。 比方说对这个数。如果它按位取反的结果,就是说,原来是0的变1。 原来是1的变0。变成这个数了。 所以如果我们对025, 这个8进制的数,进行按位取反运算的话,我们得到的就是这样一个数。 这是一个8进制的数。我们注意一下。这是取反运算的基本含意。 再往后看,左移运算。 所谓左移运算,就是把一个数的各个二进制位 全部左移若干位。这样的运算就叫 左移运算。当然一个数的二进制位如果左移的话就会有两个问题。 第一个问题是高位就会移到外面去。 其次呢,第一位就会空出来。那怎么解决这两个问题呢? 高位左移后溢出。溢出的部分就舍弃了。 不再起作用了。那么第一位呢,新空出来的呢,我们就补零。 比方说,对一个数,a=15 也就是这样的一个二进制数。转换成一个8位的二进制数是这样的。 如果对这个数进行左移2位的运算, 可以写成这样子,a = a<<2 左移两位。那么左移两位之后的结果是什么呢? 溢出来的两个零我就不要了。那么右边呢,新产生了位补零。这个数呢算下来就等于60。 所以说a左移两位,它的结果就变成了60。 15左移两位变成了60。 其实呀,细心的同学可能已经发现了, 每左移一位,如果这个数不溢出的话, 就相当于对这个数乘以了2。 是不是这个意思啊?左移两位呢,就相当于乘以了2的两次幂,就是4. 所以说,15左移两位因为它不会溢出,所以呢相当于乘了4 15乘以4, a 就变成了60。所以说,在一些乘以2的一些场景中,为了计算的快速 我们可以采用左移这样的运算来完成 这是左移。我们再来看一下右移。 一样的,也就是将一个数的各个二进制位全部右移若干位。那么既然是右移的话, 那么也存在两个问题。 那么右端移出来的数就被舍弃了。那么左端呢, 空出来的数就要补零。也是一样的处理。比方15, 还是这个数。 那么所定的二进制数后8位是00001111, 那么右移两位,我们得到的结果是这样的。 那么右端多移出来的那两个1呢,我们就把它舍弃掉了。 它表示呢,就是这样的。 a = a>>2 右移两位。 那么当然一样的道理,既然是左移 是乘以二,那么右移呢,在不溢出的情况下 不溢出的情况下,就相当于除以2。那么对这个数呢,就不行了。因为它有溢出了。 它溢出了两个1。所以说就不能相当于除以2了。那么关于位运算呢,我们还需要解释几个问题。 那么,第一个问题,关于右移运算的符号位的处理。 当把一个有符号的数进行右移运算时候,那个符号位应该怎么处理。 通常,它是这么来处理的。对于无符号的数,没有符号的数,右移的时候左端 左边因为空出来一些位嘛, 那肯定要放入一些0。那么对于有符号的数, 它是怎么处理的呢?如果原来的符号位是0,则左边放入0。 如果原来的符号位是1,也就是负数,那么左边呢,是放入1还是0 这个事儿呢,取决于你所用的计算机系统。 不同的系统会有不同的处理方式。那么可能的处理方式呢无非两种,第一种就是移入0。 那么我们管这种情况呢叫做逻辑右移。 大家在看到这个词的时候你就明白,OK,它右移的时候, 左边补的是0,就可以了。或者叫简单右移。 如果移入的是1呢,我们就称为算术右移。比方说在VC的环境底下, 那么它所采取的方式呢就是算术右移。 OK,这是关于位运算的第一个问题。那么第二个问题, 不同长度的数进行位运算的时候应该怎么处理呢?啊。 那么很好办。当有两个不同长度的数进行位运算的时候,系统呢 就会把这两个数啊按右端对齐,按右端对齐 来进行运算。 那么比方说a&b,a呢 是int型,b是short型,那么它们可以进行与运算吗? 按位与运算吗?可以。那么他们就按右端对齐,也就是说 这个short型贴着int型的低16位排好。 那么既然是按右端对齐,左端呢, 可能就有空出来的东西,对吧。因为short型它短嘛。 那如何进行补位呢?这个补位是这样的。如果b,这个b啊int型 short型啊是无符号的数,那么左端呢,就添0。如果它是有符号的数, 那么如果是正数的话,左端左边16位就补0。啊右边。如果它是负数的话呢, 左边16位就补1,是这样来处理的。第三个, 位运算呢还经常跟赋值运算放在一起组成复合赋值运算。 因为位运算通常要跟赋值运算放在一起使用,所以说这种情况经常发生。 那么当我们碰到这种情况的时候呢,我们就要知道它的含义就可以了。这个跟复合赋值运算的 基本的道理是一样的。你比方说a&=b,它就相当于a=a&b。 a|=b,那就相当于a=a|b。a>>=2,那就相当于a=a>>2。 同样左移也是一样的。同样异或a^=b,就相当于a=a^b。 如果碰到这种情况,我们知道就可以了。这是第三个需要说明的问题。 第四个,关于位运算的优先级。那么在这呢,我们给出来一个参考,就是跟其他的运算符 优先级呢做一个对比。那么位运算的优先级呢,取反运算最高, 啊它比算术运算符的优先级还要高一些。 然后呢是左移或者右移的运算,它比关系运算符要稍微高一些。然后呢 是按位与或者按位异或或者按位或运算,最后呢是逻辑运算符。 大概是这样一个由高到低的一个顺序,那么 当然标准的答案呢,请大家参考运算符优先级列表。 那么最后呢,我们介绍一下位运算的 作用,啊位运算的作用。其实在程序里头啊, 位运算有各种各样的应用,可以写出来不同的应用。但是呢有一些应用啊还真是 非常的常见。比方说第一种,按位与运算的用途,通常啊 是用来取一个数中的某些指定的位。 比方说对于一个整数a,假设说啊它是这样来表示的,当然这是用了16位了, 比方说我们想取它的低8位,那么我就可以把这样的一个a 跟这样的一个b做一个与运算。 因为这个b的最低位全都是1,最高位全都是0。 那么做完与运算之后,我们得到的这个c恰好是只包含了 a的最低位的那些二进制位。这是与运算的一个功效。 那么或运算呢也是,对一个数据的某些位我想把它 置为1,那我就用,我就让它跟某个数去做或运算。 这个相信呢,大家都能理解。 这是与运算和或运算。那么异或运算呢, 它的用法也是这样的。通常你比方说,我们可以可以做的是, 使某些特定的位呀,使一个数某些特定的位进行 翻转。比方说我们想使这个数它的低4位进行个翻转, 那么应该怎么办呢?我们就可以与,把这个数跟这个数 进行一个异或的按位异或的运算。 我们看一下这个结果,啊如果这个数跟它做一个 按位异或的运算,我们看得到的结果恰好是把 所有这里是1的这些位全部都做了一个翻转。 啊你看,这个值它的低4位 全部是对这个值的低4位的一个翻转。那么除了这个之外呢, 按位异或还有一个很重要的用途,啊是这样的。 这个呢经常在一些 面试啊什么等等这样的场合会看到这样一个题。有两个变量,比方说a和b, a=3,b=4。现在我想要把a 和b的值进行一个互换。a和b进行互换呢, 并不难。以前我们在讲程序的时候都碰到过,比方说我们可以找一个临时的量,比方说c吧,我就可以让, 把a呢先给先赋给c,然后呢再把b呢赋给a, 然后呢再把c呢给b。 这样的话,a和b就做了一个互换。但是在这儿呢, 我要求不能使用第三个量, 只能使用a,b。 只能使用a,b,而不借助于第三个量就要实现它们的互换,那怎么办呢? 很好办,这个时候正好用到按位异或运算。 它的计算过程是这样的。先把a和b做一个异或运算, 它的值呢赋给a。 然后呢再利用这个赋完值的a同b再做一次异或的运算, 结果呢赋给b。然后呢,再利用a和b的结果呢再做一次异或的运算, 结果赋给a。那么经历过这个过程以后,a和b的值就得到了一个互换。 而且在这个过程中,我们没有借助到第三个变量。OK,这就是异或运算的一个 在数据交换过程中的一个常用的方式。 OK,那么关于位运算呢,我们就介绍这么多。需要强调的是,位运算这部分 我们是不做要求的,大家如果有兴趣,可以了解一下。好,谢谢。