【问题标题】:Behavior of bitwise shift operators when right operand is negative右操作数为负时按位移位运算符的行为
【发布时间】:2015-09-14 13:54:41
【问题描述】:

在 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?我真的很困惑。

【问题讨论】:

  • 它使用位。如果您检查 -3 位,它就像.... 1101。点很多1111 1111 1111 向右移动会将0011 移动到0000,因为在那之后它不能做任何事情。
  • 我刚刚在这里阅读了 Eric Lippert 的一篇文章。 #8 提到了移位运算符。 informit.com/articles/article.aspx?p=2425867.

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


【解决方案1】:

我将回答 Java 部分(不能代表 C#,但可能是一样的)。

移位运算符&gt;&gt;&lt;&lt; 在JLS section 15.19 中定义。引用(强调我的):

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

因此,当您移位 -3 时,就如同您移位 -3 &amp; 0x1f,即 29(仅使用右侧操作数的最低五位)。

  • a &lt;&lt; -3 的结果则为2^29 * a;对于a = 3,这是1610612736
  • a &gt;&gt; -3 的结果则为floor(a / 2^29);对于a = 3,这是0

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

【讨论】:

    【解决方案2】:

    对于 C#

    来自 C# 规范第 7.9 节 -

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-26
      • 1970-01-01
      • 2015-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多