zoukankan      html  css  js  c++  java
  • 程序员面试宝典纠错,取反操作的优先级高于移位,而非移位的优先级高于取反,整型提升蒙蔽了真相

    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
    ",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
    请按任意键继续. . .
  • 相关阅读:
    js递归遍历
    .NET Core 图片操作在 Linux/Docker 下的坑
    远程桌面连接出现CredSSP的解决方法
    端口被占用解决方案
    当遇到“无法启动 IIS Express Web 服务器。”时的解决方案
    SQL Server索引设计
    python自动化之UI自动化框架搭建四--完成(关键字驱动)
    python自动化之UI自动化框架搭建三(关键字驱动)
    python自动化之UI自动化框架搭建二(关键字驱动)
    python自动化之ui自动化框架搭建一(关键字驱动)
  • 原文地址:https://www.cnblogs.com/youngforever/p/3231337.html
Copyright © 2011-2022 走看看