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中的右移和左移操作符
下一篇: 右操作数为负时按位移运算符的行为
