💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
【35.1 “右移”运算。】 “右移”运算也是以位为单位进行运算的。位是指二进制中的某一位,位只能是0或者1。欲理解某个数“右移”运算的内部规律,必先把该数展开成二进制的格式,然后才好分析。“右移”运算的符号是“>>”,它的通用格式如下: “保存变量”=“被移数”>>n; 运算规律是:“被移数”先被复制一份放到某个隐蔽的临时变量(也称作寄存器),然后对此临时变量展开成二进制的格式,左边是高位,右边是低位,此二进制格式的临时变量被整体由左往右移动了n位,原来左边由于数据位移动而新空出的高n位数据被直接填入0,而右边由于数据位移动而导致低n位数据被直接覆盖,最后再把移位运算的结果存入“保存变量”。多问一句,这行代码执行完毕后,“保存变量”和“被移数”到底哪个变量发生了变化,哪个变量维持不变?大家记住,只有赋值语句“=”左边的“保存变量”发生数值变化,而右边的“被移数”没有发生变化,因为“被移数”被操作的不是它自己本身,而是它的复制品替身(某个隐蔽的临时变量,也称寄存器)。 上述通用格式中的n代表被一次右移的位数,可以取0,当n等于0的时候,代表右移0位,其实就是数值维持原来的样子没有发生变化。 现在举一个完整的例子来分析“>>”右移运算的规律。有两个unsigned char类型的变量a和b,它们的数值都是十进制的5,求a=a>>1和b=b>>2的结果分别是多少?分析步骤如下: 第一步:先把a和b变量原来的数值以二进制的格式展开。十进制转二进制的方法请参考前面第14,15,16节的内容。 a变量是十进制5,它的二进制格式是: 00000101。 b变量是十进制5,它的二进制格式是: 00000101。 第二步:将a右移1位,将b右移2位。 (1)a=a>>1,就是将a右移1位。 a右移前是 -> 00000101 a右移1位后是 -> 00000010 结果分析:把二进制的00000010转换成十六进制是:0x02。转换成十进制是2。所以a初始值是5,右移1位后的结果是2。 (2)b=b>>2,就是将b右移2位。 b右移前是 -> 00000101 b右移2位后是 -> 00000001 结果分析:把二进制的00000001转换成十六进制是:0x01。转换成十进制是1。所以b初始值是5,右移2位后的结果是1。 **【35.2** **“右移”与除法的关系。】** 左移一位相当于乘以2,而右移跟左移恰恰相反,右移一位相当于除以2,注意,这里的除法是整除,不带小数点的。比如上面例子,5右移1位就变成了2(相当于5整除2等于2),5右移2位就变成了1(相当于5整除2再整除2等于1)。这个现象背后的规律是:在右移运算中,每右移1位就相当于整除2,右移2位相当于整除2再整除2,右移3位相当于整除2再整除2再整除2......以此类推。这个规律反过来从除法的角度看,也是成立的:某个数整除2,就相当于右移1位,某个数整除2再整除2相当于右移2位,某个数整除2再整除2再整除2相当于右3位......以此类推。那么问题来了,同样是达到整除2的运算结果,从运算速度的角度对比,“右移”和“整除”哪家强?答案是:一条右移语句的运算速度比一条整除语句的运算速度要快很多倍。 **【35.3** **“右移”的常见应用:不同数据类型之间的分解。】** 比如有一个双字节unsigned int类型的变量c,它的初始值是0x1234,要把它分解成两个unsigned char单字节的类型数据H和L,其中H是高8位字节,L是低8位字节,分解后H应该等于0x12,L应该等于0x34,此程序如何写?就需要用到右移。程序分析如下: unsigned char H; //单字节 unsigned char L; //单字节 unsigned int c=0x1234; //双字节 L=c; //c的低8位直接赋值给单字节的L H=c>>8; //c先把高8位右移到低8位,然后再把这8位数据赋值给H 程序运行结果:H就等于十六进制的0x12,十进制是18。L就等于十六进制的0x34,十进制是52.提一个问题,请问执行完上述最后一条语句H=c>>8后,此时c的值是多少?答案是c仍然等于0x1234,因为c本身没有发生变化,只要它没有赋值给它自己,执行完语句后就不会改变它自己本身,也就是本节开篇就提到的:“被移数”被操作的不是它自己本身,而是它的复制品替身(某个隐蔽的临时变量,也称寄存器)。 **【35.4** **右移运算的“右移简写”。】** 当被移数是“保存变量”时,存在“右移简写”。 “保存变量”=“保存变量”>>n; 上述右移简写如下: “保存变量”>>=n; 比如: unsigned char d=8; unsigned char e=8; d>>=1; //就相当于d=d>>1; e>>=2; //就相当于e=e>>2; 【35.5 例程练习和分析。】 现在编写一个程序来验证刚才讲到的“右移”运算: 程序代码如下: /\*---C语言学习区域的开始。-----------------------------------------------\*/ void main() //主函数 { unsigned char a=5; unsigned char b=5; unsigned char H; //单字节 unsigned char L; //单字节 unsigned int c=0x1234; //双字节 unsigned char d=8; unsigned char e=8; //右移运算中蕴含着整除2的规律。 a=a>>1; //a右移1位,相当于a=a/2,从原来的5变成了2。 b=b>>2; //b右移2位,相当于b=b/2/2,从原来的5变成了1。 //右移的常见应用:不同变量类型的分解。 L=c; //c的低8位直接赋值给单字节的L H=c>>8; //c先把高8位右移到低8位,然后再把这8位数据赋值给H //右移简写。 d>>=1; //就相当于d=d>>1; e>>=2; //就相当于e=e>>2; View(a); //把第1个数a发送到电脑端的串口助手软件上观察。 View(b); //把第2个数b发送到电脑端的串口助手软件上观察。 View(H); //把第3个数H发送到电脑端的串口助手软件上观察。 View(L); //把第4个数L发送到电脑端的串口助手软件上观察。 View(d); //把第5个数d发送到电脑端的串口助手软件上观察。 View(e); //把第6个数e发送到电脑端的串口助手软件上观察。 while(1) { } } /\*---C语言学习区域的结束。-----------------------------------------------\*/ 在电脑串口助手软件上观察到的程序执行现象如下: 开始... 第1个数 十进制:2 十六进制:2 二进制:10 第2个数 十进制:1 十六进制:1 二进制:1 第3个数 十进制:18 十六进制:12 二进制:10010 第4个数 十进制:52 十六进制:34 二进制:110100 第5个数 十进制:4 十六进制:4 二进制:100 第6个数 十进制:2 十六进制:2 二进制:10 分析: 通过实验结果,发现在单片机上的计算结果和我们的分析是一致的。 【35.6 如何在单片机上练习本章节C语言程序?】 直接复制前面章节中第十一节的模板程序,练习代码时只需要更改“C语言学习区域”的代码就可以了,其它部分的代码不要动。编译后,把程序下载进带串口的51学习板,通过电脑端的串口助手软件就可以观察到不同的变量数值,详细方法请看第十一节内容。