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

Des*_*tor 0 c# c++ java bit-shift bitwise-operators

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

#include <iostream>
int main()
{
    int s(9);
    std::cout<<(s<<-3);
}
Run Code Online (Sandbox Code Playgroud)

g ++给出以下警告:

[Warning] left shift count is negative [enabled by default]
Run Code Online (Sandbox Code Playgroud)

MSVS 2010发出以下警告:

warning c4293: '<<' : shift count negative or too big, undefined behavior
Run Code Online (Sandbox Code Playgroud)

现在我好奇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);
    }
}
Run Code Online (Sandbox Code Playgroud)

计划成果:

1610612736
0
Run Code Online (Sandbox Code Playgroud)

C#轮到:

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

输出:

1610612736
0
Run Code Online (Sandbox Code Playgroud)

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

Tun*_*aki 6

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

移位运算符>><<在JLS定义部分15.19.引用(强调我的):

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

因此,当您进行移位时-3,就好像您正在移位-3 & 0x1f,即29(仅使用右侧操作数的五个最低位).

  • 结果a << -32^29 * a; 因为a = 3,这是1610612736.
  • 结果a >> -3floor(a / 2^29); 因为a = 3,这是0.

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