int promotion: Is the following well-defined?

c, c99, standards

Solution

The promotion wins.

Says section 5.2.4.2.1 about the constants `USHRT_MAX` etc.:

The values given below shall be replaced by constant expressions suitable for use in `#if` preprocessing directives. Moreover, except for `CHAR_BIT` and `MB_LEN_MAX`, the following shall be replaced by expressions that have the same type as would an expression that is an object of the corresponding type converted according to the integer promotions.

So the multiplication is on `int`s, and involves no unsigned operands, unambiguously, there is no conforming way to implement `USHRT_MAX` to get an operation involving unsigned operands if `USHRT_MAX < INT_MAX`. Thus you have overflow, and undefined behaviour.

Regarding the added question

EDIT: What should happen in the following case?

unsigned short lhs = USHRT_MAX;
unsigned short rhs = USHRT_MAX;
unsigned short product = lhs * rhs;

That is exactly the same situation. The operands of `*` are subject to the integer promotions, all values of type `unsigned short` can be represented as `int`s by the assumption on the values of `USHRT_MAX` and `INT_MAX`, so the multiplication is on `int`s, and with the specified values overflows.

You need to convert at least one operand to an unsigned type that is not promoted to `int` in oerder to have the multiplication be performed on unsigned operands.

Problem

Suppose that on a C implementation (e.g. on a x86 C compiler) `USHRT_MAX = 65535` and `INT_MAX = 2147483647`. Is, then, the following statement well-defined? ``` unsigned short product = USHRT_MAX * USHRT_MAX; ``` According to the following in the C99 standard both operands are promoted to `int` (since `int` can represent all possible values of `unsigned short`) and, therefore, the result is not well-defined, since an overflow will occur (`65535 ^ 2 = 4294836225 > 2147483647`), which means that the value of `product` is not well-defined: 6.3.1.1-1 If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.(48) All other types are unchanged by the integer promotions. 48) The integer promotions are applied only: as part of the usual arithmetic conversions, to certain argument expressions, to the operands of the unary +, -, and ~ operators, and to both operands of the shift operators, as specified by their respective subclauses. However, according to the following, the result is well-defined, since computations involving unsigned operands do not overflow: 6.2.5-9 The range of nonnegative values of a signed integer type is a subrange of the corresponding unsigned integer type, and the representation of the same value in each type is the same.(31) A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type. Does the variable `product` in the aforementioned statement have a well-defined value? EDIT: What should happen in the following case? ``` unsigned short lhs = USHRT_MAX; unsigned short rhs = USHRT_MAX; unsigned short product = lhs * rhs; ```

Original source