The shift operators in Java have the following properties (, according to The Java Language Specification (JLS), §15.19, "Shift Operators") [JLS 2005]:
- The
>>
right shift is an arithmetic shift; the>>>
right shift is a logical shift. - The types
boolean
,float
, anddouble
cannot use the bit-shifting operators. - When the value to be shifted is of type
int
, only the five lowest-order bits of the right-hand operand are used as the shift distance. That is, the shift distance is the value of the right-hand operand masked by 31 (0x1F). The shift distance actually used is consequently always in the range 0 to 31, inclusive. - When the value to be shifted (left - operand) is type
long
, only the last 6 bits of the right-hand operand are used to perform the shift. The shift distance is the value of the right-hand operand masked by 63 (0x3F). The shift distance actually used is consequently always in the range 0 to 63, inclusive.
The value to the right of a shift operation must be within the appropriate range for the type of the numeric value to the left of the shift operation. That is, if the left numeric type is a long
, the right value must be within the range [0, 63]; otherwise, otherwise the right value must be within the range [0, 31].
Arithmetic vs. Logical Shift
The JLS [JLS 2005] defines the behavior of the arithmetic shift operator as follows:
The value of n>>s is n right-shifted s bit positions with sign-extension. The resulting value is ⌊ n / 2 s ⌋. For nonnegative values of n, this is equivalent to truncating integer division, as computed by the integer division operator /, by two to the power s.
...
In this noncompliant code example, method countOneBits
loops forever on negative inputs because the >>
operator performs an arithmetic shift rather than a logical shift.:
Code Block | ||
---|---|---|
| ||
static int countOneBits(long value) { int bits = 0; while (value != 0) { bits += value & 1L; value >>= 1; // signedSigned right-shift, by one } return bits; } |
...
This compliant solution uses the logical shift operator >>>
, which clears vacated bits (that is, shifts in zero-bits on the left).:
Code Block | ||
---|---|---|
| ||
static int countOneBits( long value ) { int bits = 0; while (value != 0) { bits += value & 1L; value >>>= 1; } return bits; } |
...
Code Block | ||
---|---|---|
| ||
byte b = /* initializeInitialize */; int result = b >>> 2; |
...
Code Block | ||
---|---|---|
| ||
byte b = /* initializeInitialize */; int result = ((int) b & 0xFF) >>> 2; |
...
When the left-hand operand is of type int
, the right-hand operand (exp
) is masked by 31 (0x1F). A left operand of type long
causes the right operand (exp
) to be masked by 63 (0x3F). Consequently, when the shift distance is greater than the number of bits in the left -hand operand, the shift distance is interpreted as being (distance % number_of_bits)
.
...
This noncompliant code example fails to perform explicit range-checking to avoid truncation of the shift distance.:
Code Block | ||
---|---|---|
| ||
public int doOperation(int exp) { // computeCompute 2^exp int temp = 1 << exp; // doDo other processing return temp; } |
...
This compliant solution range checks the shift distance to avoid unexpected behavior.:
Code Block | ||
---|---|---|
| ||
public int doOperation(int exp) throws ArithmeticException { if ((exp < 0) || (exp >= 32)) { throw new ArithmeticException("Exponent out of range"); } // safelySafely compute 2^exp int temp = 1 << exp; // doDo other processing return temp; } |
Explicit range-checking for arithmetic operations is detailed in the rule NUM00-J. Detect or prevent integer overflow.
...
This noncompliant code example tries to shift the value -1
by increasing the value of i
until, after 32 iterations, the programmer believes the result would become 0. The loop actually never terminates because an attempt to shift a value of type int
by 32 bits results in the original value (that is, -1−1) rather than the expected value 0 [Bloch 2005]. This is because only the least significant 5 bits of i
is are considered when the shift occurs, and when i
reaches the value 32, the 5 least significant bits have the value 0.
...
This compliant solution does 32 shifts in succession, achieving the value 0 on the 32nd iteration.:
Code Block | ||
---|---|---|
| ||
for (int val = -1; val != 0; val <<= 1) { /* ... */ } |
Multiplication and Division
See rule NUM01-J. Do not perform bitwise and arithmetic operations on the same data.
...
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
NUM14-J | lowLow | probableProbable | mediumMedium | P4 | L3 |
Automated Detection
Automatic detection of shift operators is straightforward. Sound determination of whether the usage of those shift operators correctly reflects the intent of the programmer is infeasible in the general case. Heuristic warnings could be useful.
...
Bibliography
...