使用左右移位运算符时的优先级

时间:2015-10-31 07:47:00

标签: c bit-shift operator-precedence

我想知道以下C程序的输出是如何32的。请为我提供一步一步的指导。

main()
{
    int a=4,b=2;
    a=b<<a+b>>2;
    printf("%d",a);
}

3 个答案:

答案 0 :(得分:5)

询问优先级+的优先级高于<<>>,因此表达式为

b << (a + b) >> 2

评估为

2 << (4 + 2) >> 2 = 2 << 6 >> 2

现在,再次决定首先评估哪个部分 - <<>>具有相同的优先级,但 associativity 来到抢救,对于<<>>,它是从左到右,所以这意味着首先评估最左边的运算符:

(2 << 6) >> 2 = 128 >> 2 = 32

编辑:完成所有操作,尊重优先级关联性,原始表达式b<<a+b>>2会读取以下完全括号内容:

((b << (a + b)) >> 2

对于未来的疑虑,拥有table showing both precedence and associativity非常有帮助。或者只是使用一些“多余的”括号来使表达对人类更具可读性;)

答案 1 :(得分:3)

int a=4,b=2;
a=b<<a+b>>2;

这里b是2 ==(0000 0000 0010)

a = 2<<(4+2)>>2; // as ADD(+) is having higher precedence so first we will solve addtion.
a = 2 << 6 >> 2;

a = ((2 << 6) >> 2); //<<  >>, Associativity (left-to-right) so first solve (2 << 6).

向左移动6位

After solving 2<<6  (0000 1000 0000)  == 128  
                          ^^^^ ^^   <-- left  

向右移动2位

Now 128>>2  (0000 0010 0000)  == 32.  
        Right -->  ^^

答案 2 :(得分:0)

如果你看一下这段代码的反汇编:

    31:                 int a = 4, b = 2;
00007FFE91FC449C C7 45 24 04 00 00 00 mov         dword ptr [rbp+24h],4  
00007FFE91FC44A3 C7 45 20 02 00 00 00 mov         dword ptr [rbp+20h],2  
    32:                 a = b << a + b >> 2;
00007FFE91FC44AA 8B 4D 24             mov         ecx,dword ptr [rbp+24h]  
00007FFE91FC44AD 8B 45 20             mov         eax,dword ptr [rbp+20h]  
00007FFE91FC44B0 03 C8                add         ecx,eax  
00007FFE91FC44B2 83 E1 1F             and         ecx,1Fh  
00007FFE91FC44B5 8B 45 20             mov         eax,dword ptr [rbp+20h]  
00007FFE91FC44B8 D3 E0                shl         eax,cl  
00007FFE91FC44BA 8B C8                mov         ecx,eax  
00007FFE91FC44BC C1 F9 02             sar         ecx,2  
00007FFE91FC44BF 89 4D 24             mov         dword ptr [rbp+24h],ecx 

如您所见,+运算符首先完成,<<>>运算符具有相同的优先级并且具有从左到右的关联性(因此从左到右执行)右)所以你的代码可以简化为:

main()
{
    int a = 4, b = 2;
    a = a + b; //6
    a = b << a; //128
    a = a >> 2; //32
    printf("%d", a);
}

请注意,除了上次分配和删除之外,功能中没有实际的分配。

您的代码与将其编写为a = b << (a + b) >> 2;的代码相同。