2013-08-01 21:17:41
在程序员面试宝典的第五章,5.4节有一道题,指出左移操作符>>的优先级高于按位取反操作符~,是错误的,是整型提升造成的假象;左移>>的优先级是低于取反~的,正如在C++primer等其他教材上所说的,下面给出详细说明。
整型提升后,先取反、再左移的结果与先左移、再取反的结果相等,因而,使人误以为左移操作符>>的优先级高于按位取反操作符~。
注意点:
- 在执行算术操作之前,将二元操作符(如算术或逻辑操作符)的两个操作数转换为同一类型,并使其表达式的值也具有相同的类型。
- 整型提升就是,就是对于所有比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 ",b); 6 7 return 0; 8 }
运行结果:
1 b = 245 2 请按任意键继续. . .
书中的解释,说是优先级造成的,说是因为左移操作符>>的优先级高于按位取反操作符~,因此对0xa5先取反,再移位,便可得到1111 0101,即十进制的245.
在下面的代码中,用括号指定操作数的结合,如下:
unsigned char a = 0xa5;
unsigned char b = ~a>>4;
unsigned char c = (~a)>>4;
unsigned char d = ~(a>>4);
运行结果显示ac完全相同,这说明并非是因为>>的优先级并不比~的高;
因此,有如下疑问:
按照先取反再左移,结果为什么不是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类型左移"<<endl; 6 unsigned char a = 0xa5; 7 unsigned char b = ~a>>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<<endl<<(int)b<<endl<<(int)c<<endl<<(int)d<<endl<<(int)e<<endl<<(int)f<<endl; 14 15 //对unsigned char类型右移 16 cout<<"对unsigned char类型右移"<<endl; 17 unsigned char a0 = 0xa5; 18 unsigned char b0 = ~a0<<4; 19 unsigned char c0 = (~a0)<<4; 20 unsigned char d0 = ~(a0<<4); 21 unsigned char e0 = ~a0; 22 unsigned char f0 = e0<<4; 23 24 cout<<(int)a0<<endl<<(int)b0<<endl<<(int)c0<<endl<<(int)d0<<endl<<(int)e0<<endl<<(int)f0<<endl; 25 26 //对int类型,符号位为0的情况 27 int a1 = 0xa7; 28 int b1 = ~a1>>4; 29 int c1 = (~a1)>>4; 30 int d1 = ~(a1>>4); 31 int e1 = ~a1; 32 int f1 = e1>>4; 33 34 cout<<"a1 = "<<a1<<" b1 = "<<b1<<" c1 = "<<c1<<" d1 = "<<d1<<" e1 = "<<e1<<" f1 = "<<f1<<endl; 35 36 cout<<"a1 = "; 37 PrintBinaryOfInt(a1); 38 cout<<"b1 = "; 39 PrintBinaryOfInt(b1); 40 cout<<"c1 = "; 41 PrintBinaryOfInt(c1); 42 cout<<"d1 = "; 43 PrintBinaryOfInt(d1); 44 cout<<"e1 = "; 45 PrintBinaryOfInt(e1); 46 cout<<"f1 = "; 47 PrintBinaryOfInt(f1); 48 49 //对int类型,符号位为1的情况 50 int a2 = 0xa7000000; 51 int b2 = ~a2>>4; 52 int c2 = (~a2)>>4; 53 int d2 = ~(a2>>4); 54 int e2 = ~a2; 55 int f2 = e2>>4; 56 57 cout<<"a2 = "<<a2<<" b2 = "<<b2<<" c2 = "<<c2<<" d2 = "<<d2<<" e2 = "<<e2<<" f2 = "<<f2<<endl; 58 59 cout<<"a2 = "; 60 PrintBinaryOfInt(a2); 61 cout<<"b2 = "; 62 PrintBinaryOfInt(b2); 63 cout<<"c2 = "; 64 PrintBinaryOfInt(c2); 65 cout<<"d2 = "; 66 PrintBinaryOfInt(d2); 67 cout<<"e2 = "; 68 PrintBinaryOfInt(e2); 69 cout<<"f2 = "; 70 PrintBinaryOfInt(f2); 71 72 //对int类型,测试右移操作符 73 int a3 = 0xa7; 74 int b3 = ~a3<<4; 75 int c3 = (~a3)<<4; 76 int d3 = ~(a3<<4); 77 int e3 = ~a3; 78 int f3 = e3<<4; 79 80 cout<<"a3 = "<<a3<<" b3 = "<<b3<<" c3 = "<<c3<<" d3 = "<<d3<<" e3 = "<<e3<<" f3 = "<<f3<<endl; 81 82 cout<<"a3 = "; 83 PrintBinaryOfInt(a3); 84 cout<<"b3 = "; 85 PrintBinaryOfInt(b3); 86 cout<<"c3 = "; 87 PrintBinaryOfInt(c3); 88 cout<<"d3 = "; 89 PrintBinaryOfInt(d3); 90 cout<<"e3 = "; 91 PrintBinaryOfInt(e3); 92 cout<<"f3 = "; 93 PrintBinaryOfInt(f3); 94 95 //对unsigned char类型左移 96 cout<<"对unsigned char类型左移"<<endl; 97 unsigned char a4 = 0xa5; 98 unsigned char b4 = ~a4>>(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<<endl<<(int)b4<<endl<<(int)c4<<endl<<(int)d4<<endl<<(int)e4<<endl<<(int)f4<<endl; 105 106 }
运行结果如下:
对unsigned char类型左移 165 245 245 245 90 5 对unsigned char类型右移 165 160 160 175 90 160 a1 = 167 b1 = -11 c1 = -11 d1 = -11 e1 = -168 f1 = -11 a1 = 00000000 00000000 00000000 10100111 b1 = 11111111 11111111 11111111 11110101 c1 = 11111111 11111111 11111111 11110101 d1 = 11111111 11111111 11111111 11110101 e1 = 11111111 11111111 11111111 01011000 f1 = 11111111 11111111 11111111 11110101 a2 = -1493172224 b2 = 93323263 c2 = 93323263 d2 = 93323263 e2 = 1493172223 f2 = 93323263 a2 = 10100111 00000000 00000000 00000000 b2 = 00000101 10001111 11111111 11111111 c2 = 00000101 10001111 11111111 11111111 d2 = 00000101 10001111 11111111 11111111 e2 = 01011000 11111111 11111111 11111111 f2 = 00000101 10001111 11111111 11111111 a3 = 167 b3 = -2688 c3 = -2688 d3 = -2673 e3 = -168 f3 = -2688 a3 = 00000000 00000000 00000000 10100111 b3 = 11111111 11111111 11110101 10000000 c3 = 11111111 11111111 11110101 10000000 d3 = 11111111 11111111 11110101 10001111 e3 = 11111111 11111111 11111111 01011000 f3 = 11111111 11111111 11110101 10000000 对unsigned char类型左移 165 245 245 245 90 5 请按任意键继续. . .