Behavior of bitwise shift operators when right operand is negative
In C & C++, if right operand is negative when using >>
and <<
(shift right & shift left operator), behavior of program is undefined. Consider following program:
#include <iostream>
int main()
{
int s(9);
std::cout<<(s<<-3);
}
g++ gives following warning:
[Warning] left shift count is negative [enabled by default]
MSVS 2010 gives following warning:
warning c4293: '<<' : shift count negative or too big, undefined behavior
Now I am curious about what happens in Java and C#?
I've tried 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);
}
}
Outcome of program:
1610612736
0
C#'s turn:
namespace left_shift_nagative
{
class Program
{
static void Main(string[] args)
{
int s = 3;
Console.WriteLine(s << -3);
Console.WriteLine(s >> -3);
}
}
}
Output:
1610612736
0
How the output 1610612736 comes? What is happening here? What the Java Language Specification (JLS) and C# Language Specification or standard says about this? How << and >> operator works when negative shift count is given in Java & C#? How I got output 0 when right shift is used? I am really getting confused.
I will answer about the Java part (can't speak for C# but it is probably the same).
The shift operators >>
and <<
are defined in JLS section 15.19. Quoting (emphasis mine):
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 .
Therefore, when you are shifting by -3
, it is exactly as if you were shifting by -3 & 0x1f
, which is 29 (only the five lowest-order bits of the right-hand operand are used).
a << -3
is then 2^29 * a
; for a = 3
, this is 1610612736
. a >> -3
is then floor(a / 2^29)
; for a = 3
, this is 0
. Note that when the promoted type of the left-operand is long
, and not int
, the mask value used is 0x3f
(only the six lowest-order bits of the right-hand operand are used).
For C#
From the C# spec Section 7.9 -
For the predefined operators, the number of bits to shift is computed as follows:
x
is int
or uint
, the shift count is given by the low-order 5 bits of count
. In other words, the shift count is computed from count & 0x1F
x
is long
or ulong
, the shift count is given by the low-order 6 bits of count
. In other words, the shift count is computed from count & 0x3F
This means that the sign of the shift is ignored. In fact as pointed out by Jon Skeet in the annotated spec, the following code will wrap after i == 31
due to the bit masking defined by the spec.
for (int i = 0; i < 40; i++)
{
Console.WriteLine(int.MaxValue >> i);
}
链接地址: http://www.djcxy.com/p/72504.html
上一篇: SQL Server中的右移和左移操作符
下一篇: 右操作数为负时按位移运算符的行为