在 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 section 15.19 中定义.引用(强调我的):
If the promoted type of the left-hand operand is int, then only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x1f (0b11111). The shift distance actually used is therefore always in the range 0 to 31, inclusive.
因此,当您按 -3
移动时, 就好像你在移动 -3 & 0x1f
, 即 29(仅使用右侧操作数的最低五位)。
a << -3
的结果然后是2^29 * a
;对于a = 3
, 这是1610612736
.a >> -3
的结果然后是floor(a / 2^29)
;对于a = 3
, 这是0
.
请注意,当左操作数的提升类型为 long
时,而不是 int
, 使用的掩码值为 0x3f
(仅使用右侧操作数的最低六位)。
关于java - 右操作数为负时位移运算符的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32566640/