This question already has an answer here:
int z = 1;
z <<= 31;
z >>= 31;
printf ("%d\n",z);
When I run the code, z=-1
, why?
This question already has an answer here:
int z = 1;
z <<= 31;
z >>= 31;
printf ("%d\n",z);
When I run the code, z=-1
, why?
Right, shifting a signed integer and negative numbers is implementation defined I believe.
Your implementation is probably doing a sign bit extension when you shift to the right.
So instead of shifting in zeros from the left, it's shifting in the sign bit.
z <<= 31;
is probably setting the sign bit to 1, thenz >>= 31;
is shifting in ones from the left so you end up with a bit pattern of0xFFFFFFFF
which is interpreted as the value-1
on your platform (which probably uses two's complement).Assuming 32-bit
int
s, this is undefined behavior in C11 and C++11, but implementation-defined in C++14.C11 §6.5.7/p4 (quoting N1570):
The C++11 rule in N3337 §5.8 [expr.shift]/p2 is pretty much identical. Since 231 isn't usually representable in a signed 32-bit
int
, the behavior is undefined.C++14 §5.8 [expr.shift]/p2 (quoting N3936; see also CWG issue 1457):
As 231 is representable in an unsigned 32-bit
int
, the behavior is defined and the result is 231 converted to (signed)int
; this conversion is implementation-defined per §4.7 [conv.integral]/p3. In a typical system using two's complement you'd get -231, in which case the subsequent right shift is also implementation defined since the value is negative. If an arithmetic shift is performed, then the sign bit is shifted in, and you end up with-1
.If you were using
unsigned int
you'll get the same results. The issue is you have used<<
to left shift a 31 bits plus a bit sign 31 times to the left. This is unsigned behaviour, as you have lost the most significant bit on the left side into the sign bit (this is what are you getting as the result of that undefined behaviour)When you do a right shift, this is made differently when you have signed integers (you get a copy of the sign bit into the most significant bit) than when you have unsigned ones (you get a zero bit shifted from the left side). Normally, this means you get a right arithmetical shift instruction for signed integers (equivalent to a divide by two) when you do a right shift and a right logical shift instruction (equivalent also to a divide by two, but with unsigned numbers) when you do a right shift with unsigned numbers.
just try the same declaring z as
unsigned int z;
and you'll get the expected behaviour.Assuming you are talking about
int
being 32-bit or smaller here. (Ifint
is larger then this code is well-defined and results inz
being1
).In C and C++,
z <<= 31
is defined asz = z << 31
.In C11,
<<
is explained as (6.5.7/4):In this case
E1
isz
which is1
, andE2
is31
. However, 231 is not representable in a 32-bitint
whose maximum value is 231 - 1, therefore the behaviour is undefined.When undefined behaviour occurs anything can happen, ranging from you seeing unexpected output, to the program crashing, to missiles being launched, and so on.
In C99, C++98 and C++03
<<
has a similar definition;1 << 31
is undefined behaviour in all of those (for 32-bit or smaller ints).In C++11 and C++14 there is an option you can test,
std::numeric_limits<int>::is_modulo
. If this istrue
then in some people's opinion, it means that integer overflow is no longer undefined, and so the result of1 << 31
must beINT_MIN
. For further discussion of this topic see this thread.Supposing we get this far (i.e. your system has 32-bit ints, and
std::numeric_limits<int>::is_modulo == true
, and you side with those who interpret the standard as saying that there is no UB on signed int overflow in this situation) then we have the following:Now to discuss
z >>= 31
. This is defined asz = z >> 31;
. In C++11 5.8/3:Since
INT_MIN
is a negative value, the behaviour is implementation-defined. This means that your implementation must document what it does, so you can consult your compiler's documentation to find out what is happening here.A likely explanation is that it performs an arithmetic shift, which means that the bits are shifted right, but the sign bit retains its value. This means you end up with all-bits-one, which is
-1
in two's complement.this is because sign copy mechanism, when ever you are left shifting z by 31 times, 1 is shifted from 0th bit position to 31st bit position. now on you are having 1 in 31st bit which will be treated as negative numbers. and in negative numbers, sign copy mechanism is used, in which if you right shift on negative numbers, sign bit is preserved. so you are having 1's in every bit position which is -1 in decimal.
Assuming
int
is 32 bit and two's complement representation is used, the left shift is undefined behavior in C because the result if not representable in theint
type. From the standard:In practice, it is likely to result in
0x80000000
, which is treated as a negative number.And right-shifting of negative integers is implementation-defined behavior:
In C++ left shift is defined in a similar way till C++14, as @T.C. mentioned (or, with some restrictions, might be even till C++11, as @MattMcNabb wrote).
But even if left-shift is defined and
0x8000000
is the expected value, the result of a right shift of a negative number is still implementation-defined.