3

Take the following code fragment.

short int a, b = 30001, c = 30002, d = 30003;
a = b + c - d;

Assume that short int is 16 bits and int is 32 bits. Is this undefined behaviour in C++?

My reading of the C standard is that b and c must both be promoted to int, so the entire calculation must be performed using int arithmetic. The final value fits in a short, so UB does not occur.

I cannot find corresponding language in the C++ standard. The section on integer promotion (n3797 S4.5/1) says:

A prvalue of an integer type other than bool, char16_t, char32_t, or wchar_t whose integer conversion rank (4.13) is less than the rank of int can be converted to a prvalue of type int if int can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of type unsigned int.

The emphasis is mine. Can be is not the same as must be.

S 5/10 says:

Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield result types in a similar way. The purpose is to yield a common type, which is also the type of the result. This pattern is called the usual arithmetic conversions, which are defined as follows:

...

— Otherwise, the integral promotions (4.5) shall be performed on both operands. Then the following rules shall be applied to the promoted operands:

— If both operands have the same type, no further conversion is needed.

If the values are not promoted then the consequence is that the intermediate value of the calculation exceeds the range for short int, which means that the answer should be yes, this is UB.

It also means there is an unlikely difference between C and C++. It is not mentioned in the Compatibility section.

All the other questions I could find involved mixtures of types, signed/unsigned, etc. Nothing specifically on this question. It arose in my answer to this.

Any takers?

Community
  • 1
  • 1
david.pfx
  • 10,520
  • 3
  • 30
  • 63
  • 1
    Your quote in 5/10 uses **shall be**. That's not optional. – Ben Voigt May 13 '14 at 15:22
  • Also, it's not necessary for the result to fit in a `short`. 4.7 says "If the destination type is signed, the value is unchanged if it can be represented in the destination type (and bit-field width); otherwise, the value is implementation-defined.". **Implementation-defined value** is very different from **undefined behavior**. – Ben Voigt May 13 '14 at 15:35
  • @BenVoigt: Is that all there is? A single mention of __shall be__? The C standard makes this quite explicit, but C++ doesn't even have a footnote for this. Footnote 62 covers some other types, but not char or short. – david.pfx May 14 '14 at 00:02
  • @BenVoigt: Again, colour me surprised. It's UB if an intermediate result exceeds the range but not UB if the final value exceeds it. – david.pfx May 14 '14 at 00:03
  • @davidpfx: It doesn't have to do with intermediate or final values. Loss of precision converting between types is safe, but performing arithmetic operations that overflow is not. – Ben Voigt May 14 '14 at 01:41
  • @BenVoigt: "Converting between types" == storing final value, "arithmetic operations that overflow" == calculating intermediate values. Still surprising on the face of it. – david.pfx May 14 '14 at 23:16
  • Conversions *can* occur in the middle of the expression, for example coercion to the formal argument type of a function. You just don't have that in this example. – Ben Voigt May 14 '14 at 23:20

1 Answers1

4

Farther down in 4/5 is:

These conversions are called integral promotions.

So when 5/10 says that "integral promotions shall be performed", it means that whichever one of the listed conversions matches (there is only ever one match) is required (in this context).

The "can be" wording provides a guarantee that these conversions are possible, and does not exclude other conversions from being supported, including identity conversion. But no other conversions carry the name of integral promotion.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720