博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
程序员面试宝典纠错,取反操作的优先级高于移位,而非移位的优先级高于取反,整型提升蒙蔽了真相...
阅读量:6580 次
发布时间:2019-06-24

本文共 3903 字,大约阅读时间需要 13 分钟。

2013-08-01 21:17:41

在程序员面试宝典的第五章,5.4节有一道题,指出左移操作符>>的优先级高于按位取反操作符~,是错误的,是整型提升造成的假象左移>>的优先级是低于取反~的,正如在C++primer等其他教材上所说的,下面给出详细说明。

整型提升后,先取反、再左移的结果与先左移、再取反的结果相等,因而,使人误以为左移操作符>>的优先级高于按位取反操作符~。

注意点:

  1. 在执行算术操作之前,将二元操作符(如算术或逻辑操作符)的两个操作数转换为同一类型,并使其表达式的值也具有相同的类型。
  2. 整型提升就是,就是对于所有比int小(此处指的是位宽)的整型,包括char、signed char、unsigned char、short、unsigned short,如果该类型的所有可能的值都包括在int内(如果unsigned short为32位,int也为32位,那么此时int型就不能包括所有的unsigned short,就需提升为unsigned int),它们就会被提升为int型,否则,它们将被提升为unsigned int。

原题如下:

1 int main()2 {3     unsigned char a = 0xa5;4     unsigned char b = ~a>>4;5     printf("b = %d\n",b);6 7     return 0;8 }

运行结果:

1 b = 2452 请按任意键继续. . .

书中的解释,说是优先级造成的,说是因为左移操作符>>的优先级高于按位取反操作符~,因此对0xa5先取反,再移位,便可得到1111 0101,即十进制的245.

在下面的代码中,用括号指定操作数的结合,如下:

unsigned char a = 0xa5;

 unsigned char b = ~a>>4;
 unsigned char c = (~a)>>4;
 unsigned char d = ~(a>>4);

运行结果显示a\b\c完全相同,这说明并非是因为>>的优先级并不比~的高;

因此,有如下疑问:

按照先取反再左移,结果为什么不是5,而是245?到底谁的优先级高,此处的结果如何解释?

若将上面的左移改为右移,可以看到是先进行取反操作,再进行右移的,由此可以判断右移的优先级比取反的高;而右移与左移的优先级是相同的,可以推断取反比左移的优先级高。那么此处的结果如何解释?

疑问解惑:

实际上,此处的结果是由C++中算术转换中的整型提升造成的,在C++primer 5.12.2节有详细介绍。

在执行算术操作之前,将二元操作符(如算术或逻辑操作符)的两个操作数转换为同一类型,并使其表达式的值也具有相同的类型。

整型提升就是,就是对于所有比int小(此处指的是位宽)的整型,包括char、signed char、unsigned char、short、unsigned short,如果该类型的所有可能的值都包括在int内(如果unsigned short为32位,int也为32位,那么此时int型就不能包括所有的unsigned short,就需提升为unsigned int),它们就会被提升为int型,否则,它们将被提升为unsigned int。

对于b = ~a>>4,首先将a与4都提升为int型,对a = 0xa5,int型的a对应的二进制为0000,0000,0000,0000,0000,1010,0101,

下面是先取反、再移位时的计算过程:

~a的二进制为1111,1111,1111,1111,1111,1111,0101,1010

再左移4位即可得到0000,1111,1111,1111,1111,1111,1111,0101

将该值赋给b,因为b是unsigned char类型的,所以需要将左移后的数据转换为unsigned char型,即为1111,0101也就是十进制的245.

对于先移位再取反,同样也可根据上面的方法计算(列出二进制的计算过程),可以发现,最后得到的数据与上面的是相同的。

下面的代码中给出了int型数据移位、取反操作的验证,同样是先左移、再取反与先取反、再左移的结果是相同的,但不要因此认为左移的优先级高于取反。

记住一点,此处的结果是由于整型提升导致的,并非是移位的优先级高于取反;这也提醒我们,对算术计算之前要进行整型提升,要注意计算过程中数据的位数;因为整型提升,可能会得不到预想的结果,如上面~a>>4不是5,而是245.

下面的测试代码用于验证上面的分析,根据运行结果的显示可以印证上面的分析是正确的。

完整测试代码如下:

1 //测试移位操作符与取反操作符的优先级  2 void TestShift()  3 {  4     //对unsigned char类型左移  5     cout<<"对unsigned char类型左移"<
>4; 8 unsigned char c = (~a)>>4; 9 unsigned char d = ~(a>>4); 10 unsigned char e = ~a; 11 unsigned char f = e>>4; 12 13 cout<<(int)a<
<<(int)b<
<<(int)c<
<<(int)d<
<<(int)e<
<<(int)f<
>4; 29 int c1 = (~a1)>>4; 30 int d1 = ~(a1>>4); 31 int e1 = ~a1; 32 int f1 = e1>>4; 33 34 cout<<"a1 = "<
<<" b1 = "<
<<" c1 = "<
<<" d1 = "<
<<" e1 = "<
<<" f1 = "<
<
>(unsigned char)4; 99 unsigned char c4 = (~a4)>>(unsigned char)4;100 unsigned char d4 = ~(a4>>(unsigned char)4);101 unsigned char e4 = ~a4;102 unsigned char f4 = e4>>(unsigned char)4;103 104 cout<<(int)a4<
<<(int)b4<
<<(int)c4<
<<(int)d4<
<<(int)e4<
<<(int)f4<

 

 运行结果如下:

对unsigned char类型左移165245245245905对unsigned char类型右移16516016017590160a1 = 167 b1 = -11 c1 = -11 d1 = -11 e1 = -168 f1 = -11a1 = 00000000 00000000 00000000 10100111b1 = 11111111 11111111 11111111 11110101c1 = 11111111 11111111 11111111 11110101d1 = 11111111 11111111 11111111 11110101e1 = 11111111 11111111 11111111 01011000f1 = 11111111 11111111 11111111 11110101a2 = -1493172224 b2 = 93323263 c2 = 93323263 d2 = 93323263 e2 = 1493172223 f2 =93323263a2 = 10100111 00000000 00000000 00000000b2 = 00000101 10001111 11111111 11111111c2 = 00000101 10001111 11111111 11111111d2 = 00000101 10001111 11111111 11111111e2 = 01011000 11111111 11111111 11111111f2 = 00000101 10001111 11111111 11111111a3 = 167 b3 = -2688 c3 = -2688 d3 = -2673 e3 = -168 f3 = -2688a3 = 00000000 00000000 00000000 10100111b3 = 11111111 11111111 11110101 10000000c3 = 11111111 11111111 11110101 10000000d3 = 11111111 11111111 11110101 10001111e3 = 11111111 11111111 11111111 01011000f3 = 11111111 11111111 11110101 10000000对unsigned char类型左移165245245245905请按任意键继续. . .

 

 

 

转载于:https://www.cnblogs.com/youngforever/p/3231337.html

你可能感兴趣的文章
使用模板将Web服务的结果转换为标记语言
查看>>
inno setup 打包脚本学习
查看>>
php 并发控制中的独占锁
查看>>
React Native 0.20官方入门教程
查看>>
JSON for Modern C++ 3.6.0 发布
查看>>
Tomcat9.0部署iot.war(环境mysql8.0,centos7.2)
查看>>
我的友情链接
查看>>
监听在微信中打开页面时的自带返回按钮事件
查看>>
第一个php页面
查看>>
世界各国EMC认证大全
查看>>
最优化问题中黄金分割法的代码
查看>>
在JS中使用Ajax
查看>>
Jolt大奖获奖图书
查看>>
android中webview空间通过Img 标签显示sd卡中 的图片
查看>>
ubuntu 16.04 安装PhpMyAdmin
查看>>
安卓开启多个服务
查看>>
设置分录行按钮监听事件
查看>>
C Primer Plus 第5章 运算符、表达式和语句 5.2基本运算符
查看>>
java并发库之Executors常用的创建ExecutorService的几个方法说明
查看>>
23种设计模式(1):单例模式
查看>>