右操作数为负时位移位操作符的行为
本文关键字:位操作 操作符 操作数 | 更新日期: 2023-09-27 18:12:36
#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#中发生了什么?
I've try following program
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;和>>运算符在Java &c#吗?当使用右移时,我是如何得到输出0的?我真的很困惑。
我将回答Java部分(不能说c#,但可能是一样的)。
移位运算符>>
和<<
在JLS第15.19节中定义。引用(强调我的):
如果左操作数的提升类型为int,则只使用右操作数的最低五位作为移位距离。这就好像右操作数受到了位逻辑与操作符&(§15.22.1),掩码值为0x1f (0b11111)。因此,实际使用的移位距离始终在0到31的范围内,包括。
因此,当你通过-3
进行移位时,就像你通过-3 & 0x1f
进行移位一样,也就是29(只使用了右操作数的最低五位)。
-
a << -3
的结果是2^29 * a
;对于a = 3
,这是>>
0。 -
a >> -3
的结果是floor(a / 2^29)
;对于a = 3
,这是0
。
请注意,当左操作数的提升类型为long
而不是int
时,使用的掩码值为0x3f
(仅使用右操作数的六位最低位)。
对于c#
来自c#规范章节7.9 -
对于预定义的运算符,要移位的位数按如下方式计算:
- 当
计算的。x
的类型为int
或<<
0时,移位计数由count
的低阶5位给出。换句话说,移位计数是从count & 0x1F
- 当
计算的。x
的类型为long
或ulong
时,移位计数由count
的低阶6位给出。换句话说,移位计数是从count & 0x3F
这意味着移位的符号被忽略。事实上,正如Jon Skeet在注释规范中指出的那样,由于规范定义的位屏蔽,以下代码将在i == 31
之后包装。
for (int i = 0; i < 40; i++)
{
Console.WriteLine(int.MaxValue >> i);
}