2

If I have value declared as of type int on a 32 bit platform and perform the following:

int32_t mask;
mask = 1 << 31: // produces 2147483648 (or 0x80000000)

Can someone help me understand why the above line would produce the warning:

The result of the '<<' expression is undefined
Willam Hill
  • 1,572
  • 1
  • 17
  • 28
  • Which compiler, which language, and which version of the standard? This is implementation-defined in C++14 and undefined in all other versions of C and C++. – T.C. Oct 11 '14 at 21:50
  • 2
    @jww how is that a duplicate? The highest scoring answer explicitly states "shifts of 32 or more are undefined". This is about 31 times. The answer in this case is that the fact that a `int32_t` is a typedef for `signed long int` makes it an identical issue because it's signed. – Niels Keurentjes Oct 11 '14 at 21:51
  • Try the following to squash the warning: `mask = (int32_t)(1UL << 31);` – jww Oct 11 '14 at 21:51
  • 1
    @Niels - read the question and answer. The shift causes a sign change in both this question and the cited duplicate. But you are right... The cited question should say "more than 31...". – jww Oct 11 '14 at 21:52
  • see also [Why does (1 << 31) >> 31 result in -1?](http://stackoverflow.com/questions/26192284/why-does-1-31-31-result-in-1/) – M.M Oct 11 '14 at 21:59
  • note that the "duplicate" is a different question, however David Heffernan's answer answers both that and this – M.M Oct 11 '14 at 22:00
  • @jww yeah that was my sole point - it's not a full duplicate, but essentially the same issue for signed numbers. – Niels Keurentjes Oct 11 '14 at 22:00
  • we shoudl say that the shift will work if mask is uint32_t – pm100 Oct 11 '14 at 22:01
  • @MattMcNabb Except that the answer is outdated due to the change in the standard. – T.C. Oct 11 '14 at 22:01
  • Nominating to reopen as TC's answer is good and the linked duplicate is a different question with insufficient detail in the answer – M.M Oct 11 '14 at 22:09
  • @Matt - I'll be happy to follow your recommendation. This question needs to be disambiguated too (both [tag:c] and [tag:c++] tags). What should be done with the cited duplicate. Should it be cleaned up and then marked as a dup of this question? (I had the same feeling about some of the answers). – jww Oct 11 '14 at 22:16
  • Either way, it's crap. – Martin James Oct 11 '14 at 23:04

1 Answers1

10

231 isn't representable in a int32_t, which goes from -231 to (231-1). This is undefined behavior in C11 and C++11, and implementation-defined in C++14.

C11 §6.5.7/p4 (quoting N1570):

The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. [...] If E1 has a signed type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.

The C++11 rule in N3337 §5.8 [expr.shift]/p2 is pretty much identical. Since 231 isn't representable, the behavior is undefined.

C++14 §5.8 [expr.shift]/p2 (quoting N3936; see also CWG issue 1457):

The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are zero-filled. [...] Otherwise, if E1 has a signed type and non-negative value, and E1×2E2is 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.

As 231 is representable in an unsigned 32-bit int, the behavior is defined and the result is 231 converted to int32_t; this conversion is implementation-defined per §4.7 [conv.integral]/p3. In a typical system using two's complement you'd get -231.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • 1
    And one reason this must be undefined / implementation defined is that ones' complement and twos' complement hardware will give different results for the expression 1 << 31 when evaluated as a signed 32 bit int. http://en.wikipedia.org/wiki/Ones%27_complement – dgnuff Oct 11 '14 at 22:04
  • Is all integer overflow implementation-defined in C++14, or just this case? – M.M Oct 11 '14 at 22:08
  • @MattMcNabb Just this case. The change is in fact designed especially to make `1 << 31` legal :) – T.C. Oct 11 '14 at 22:10
  • @MattMcNabb true; the motivation for the change is to allow library writers to implement `numeric_limits::min()` and similar easily, and those people know what their implementation defines for this :) – T.C. Oct 11 '14 at 22:14
  • `- max() - 1` was difficult I guess :) – M.M Oct 11 '14 at 22:15
  • @MattMcNabb Also avoid breaking existing code due to `constexpr` additions (the optimizers may well be written to not consider `1 << 31` UB to avoid breakages, but it's UB by the standard and so requires a diagnostic in a `constexpr`) – T.C. Oct 11 '14 at 22:35
  • Confident that that the "which usually goes from" is not just usually, bit always for `int32_t`. – chux - Reinstate Monica Oct 12 '14 at 04:53
  • 1
    `int32_t` is an exact width type. C11 7.20.1.1 1 "The typedef name intN_t designates a signed integer type with width N, no padding bits, and a two’s complement representation. ...". So I still stand by that `int32_t` has a fixed range. If a system cannot support "width N, no padding bits, and a two’s complement representation", it does not support `int32_t`. – chux - Reinstate Monica Oct 12 '14 at 05:08
  • 1
    @chux Actually, even for 2's complement, the C standard allows sign-bit 1 and all-value-bit zero to be a trap representation (6.2.6.2/2). So I believe it's legal for to have a `int32_t` that has a two's complement representation but still have the range (-2^31 + 1) - (2^31 - 1), with what would usually be -2^31 being a trap representation instead. – T.C. Oct 12 '14 at 05:41
  • @T.C. Sounds like we agree `INT32_MAX` must be `2^31 - 1`. I see the strength of your point concerning `INT32_MIN`, but §7.20.2.1 1 appears quite explicit: "minimum values of exact-width signed integer types `INTN_MIN` exactly −(2N−1)". – chux - Reinstate Monica Oct 12 '14 at 16:02
  • 1
    @chux Interesting, so they implicitly ban `intN_t` from having a trap representation. – T.C. Oct 12 '14 at 23:08