Is right shifting undefined behavior for negative number in cpp and in java?

To optimize my cpp code, I’m trying to use Right Shifting in some case. Here is an example:

int main()
{
    int i = (1 - 2) >> 31;  // sizeof(int) == 4
    ...
    ...
}

I’ve printed the i and I got -1. It means that it will use 1 instead of 0 to fill in the empty position if the number is negative. In other words, -1 >> 31 works as below:

1111...1    <--- the result of (1 - 2), which is -1
1111...1    <--- -1 >> 31, 1 is used to fill in the empty position

I just want to know if this behavior is clearly defined or not?

If it is UB in cpp, how about in Java?

Yes. It is implementation-defined.

According to C++03 5.8/3 which defines right-shifting:

The value of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has
an unsigned type or if E1 has a signed type and a nonnegative value,
the value of the result is the integral part of the quotient of E1
divided by the quantity 2 raised to the power E2. If E1 has a signed
type and a negative value, the resulting value is
implementation-defined.

For more information, see this link.

In Java, behavior of >> is well-defined for negative numbers (see below).

In C++, behavior of >> is undefined for negative numbers (see answer by rsp).


Quoting Java Language Specification, §15.19. Shift Operators:

The value of n >> s is n right-shifted s bit positions with sign-extension. The resulting value is floor(n / 2s). For non-negative values of n, this is equivalent to truncating integer division, as computed by the integer division operator /, by two to the power s.

The value of n >>> s is n right-shifted s bit positions with zero-extension, where:

  • If n is positive, then the result is the same as that of n >> s.

  • If n is negative and the type of the left-hand operand is int, then the result is equal to that of the expression (n >> s) + (2 << ~s).

  • If n is negative and the type of the left-hand operand is long, then the result is equal to that of the expression (n >> s) + (2L << ~s).

By default it is signed int. The range is -32767 to 32767, bit wise range -111111111111111 to +111111111111111 the very first bit on the left acts as negative or positive indicator. And all the arithmetic operation will be done in 2’s complement method. In general negative int are represents in two complements method i.e take you example how -1 is represent.

4 Bytes = 32 bits
0000 0000 0000 0000 0000 0000 0000 0000
how represent 1
0000 0000 0000 0000 0000 0000 0000 0001
Then we invert the digits. 0 becomes 1, 1 becomes 0.
1111 1111 1111 1111 1111 1111 1111 1110
Then we add 1.
1111 1111 1111 1111 1111 1111 1111 1111
This is how -1 is represented

The right-shift of a negative number is defined to shift in 1s to the highest bit positions, then on a 2s complement representation it will behave as an arithmetic shift – the result of right-shifting by N will be the same as dividing by 2N, rounding toward negative infinity. So shifting of -1 is -1
now take an other number
For example,
if you have the 8-bit 2s complement binary number let represent -3

    0000 0011
    Then we invert the digits.
    1111 1100
    Then we add 1. 
    1111 1101

11111101 representing -3 in decimal, and you perform an arithmetic right shift by 1 to give 11111110 representing -2 in decimal, this is the same as dividing -3 by 2^1, giving -1.5 which rounds towards negative infinity resulting in -2.