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

在C&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#语言规范或标准对此有何评论? 在Java和C#中给出负移位计数时,<<和>>操作符是如何工作的? 如何在使用右移时获得输出0? 我真的很困惑。


我将回答Java部分(不能说C#,但它可能是相同的)。

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

如果左侧操作数的升级类型为int,则只有右侧操作数的五个最低位用作移位距离。 就好像右边的操作数受掩码值为0x1f(0b11111)的按位逻辑AND运算符&(第15.22.1节)。 实际使用的换档距离总是在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 (仅使用右操作数的六个最低位)。


    对于C#

    从C#规范第7.9节 -

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

  • 当的类型xintuint ,移位计数被的低位5个比特给出count 。 换句话说,移位计数从count & 0x1F计算
  • x的类型是longulong ,移位计数由低位6位count 。 换句话说,移位计数从count & 0x3F计算
  • 这意味着转移的标志被忽略。 事实上,正如Jon Skeet在注释规范中指出的那样,由于规范定义的位掩码,以下代码将在i == 31之后进行换行。

    for (int i = 0; i < 40; i++)
    {
        Console.WriteLine(int.MaxValue >> i);
    }
    
    链接地址: http://www.djcxy.com/p/72503.html

    上一篇: Behavior of bitwise shift operators when right operand is negative

    下一篇: safe left shift