Reputation: 60381
I am trying to understand exaclty how integral promotion works with arithmetic shifts operators. Particularly, I would like to know, which values of a, b, c, d, e, f, g, h
are exactly defined according to the C++14 standard, and which ones can depend on the platform/hardware/compiler (assuming that sizeof(int) == 4
).
int a = true << 3;
int b = true >> 3;
int c = true << 3U;
int d = true >> 3U;
int e = true << 31;
int f = true >> 31;
int g = true << 31U;
int h = true >> 31U;
Upvotes: 2
Views: 2387
Reputation: 148910
Following is mainly a complement to Barry's answer, that clearly explains the rules for left and right shifting.
At least fo C++11, the integral promotion of a bool gives 0 for false
and 1 for true
: 4.5 Integral promotions [conv.prom] § 6
A prvalue of type bool can be converted to a prvalue of type int, with false becoming zero and true becoming one.
So in original examples, b
, d
, f
and h
will all get a 0 value, a
and c
both get a 8
value: only perfectly defined behaviour until here.
But e
and g
will receive the unsigned value 0x80000000
, so it would be fine if you affected it to an unsigned int variable, but you are using signed 32 bits integers. So you get an integral conversion: 4.7 Integral conversions [conv.integral] §3
If the destination type is signed, the value is unchanged if it can be represented in the destination type; otherwise, the value is implementation-defined.
And unsigned 0x80000000 is not representable in a signed 64 bits integer so the result is implementation defined for e
and g
.
Upvotes: 0
Reputation: 303067
From [expr.shift]:
The type of the result is that of the promoted left operand. The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand.
The result type of shifting a bool
is always int
, regardless of what's on the right hand side. We're never shifting by at least 32 or by a negative number, so we're ok there on all accounts.
For the left-shifts (E1 << E2):
Otherwise, if E1 has a signed type and non-negative value, and E1×2E2 is representable in the corresponding unsigned type of the result type, then that value, converted to the result type, is the resulting value; otherwise, the behavior is undefined.
1×231 is representable by unsigned int
, and that's the largest left-shift we're doing, so we're ok there on all accounts too.
For the right-shifts (E1 >> E2):
If E1 has a signed type and a negative value, the resulting value is implementation-defined.
E1 is never negative, so we're ok there too! No undefined or implementation-defined behavior anywhere.
Upvotes: 3