当右操作数为负时,按位移位运算符的行为

时间:2015-09-14 13:54:41

标签: java c# c++ bitwise-operators bit-shift

在C&amp; C ++,如果在使用>><<(右移和左移运算符)时右操作数为负,则程序的行为未定义。 请考虑以下计划:

#include <iostream>
int main()
{
    int s(9);
    std::cout<<(s<<-3);
}

g ++提供以下警告:

[Warning] left shift count is negative [enabled by default]

MSVS 2010发出以下警告:

warning c4293: '<<' : shift count negative or too big, undefined behavior

现在我很想知道Java和C#会发生什么?

我尝试过以下程序

class left_shift_nagative
{
    public static void main(String args[])
    {
        int a=3;
        System.out.println(a<<-3);
        System.out.println(a>>-3);
    }
}

计划结果:

1610612736
0

C#轮到:

namespace left_shift_nagative
{
    class Program
    {
        static void Main(string[] args)
        {
            int s = 3;
            Console.WriteLine(s << -3);
            Console.WriteLine(s >> -3); 
        }
    }
}

输出:

1610612736
0

1610612736的输出如何?这里发生了什么? Java语言规范(JLS)和C#语言规范或标准对此有何看法?怎么&lt;&lt;和&gt;&gt;当Java和Java中给出负移位计数时,运算符工作。 C#?使用右移时如何输出0?我真的很困惑。

2 个答案:

答案 0 :(得分:6)

我将回答有关Java部分的内容(不能代表C#,但它可能是相同的)。

移位运算符>><<在JLS section 15.19中定义。引用(强调我的):

  

如果左侧操作数的提升类型是int,则只使用右侧操作数的五个最低位作为移位距离。就好像右手操作数受到按位逻辑AND运算符&amp; (§15.22.1),掩码值为0x1f(0b11111)。 实际使用的移位距离因此始终在0到31的范围内,包括

因此,当你移动-3时,就好像你正在移动-3 & 0x1f,即29(只使用右手操作数的五个最低位) )。

  • a << -3的结果是2^29 * a;对于a = 3,这是1610612736
  • a >> -3的结果是floor(a / 2^29);对于a = 3,这是0

请注意,当左操作数的提升类型为long而不是int时,使用的掩码值为0x3f(仅右侧的六个最低位)使用了 - 手操作数。)

答案 1 :(得分:1)

对于C#

来自C#规范第7.9节 -

  

对于预定义的运算符,要移位的位数计算如下:

     
      
  • x的类型为intuint时,移位计数由count的低位5位给出。换句话说,移位计数是从count & 0x1F
  • 计算的   
  • x的类型为longulong时,移位计数由count的低位6位给出。换句话说,移位计数是从count & 0x3F
  • 计算的   

这意味着忽略了班次的标志。事实上正如Jon Skeet在注释规范中指出的那样,由于规范定义的位掩码,以下代码将在i == 31之后换行。

for (int i = 0; i < 40; i++)
{
    Console.WriteLine(int.MaxValue >> i);
}