This expression can be found in the Example in §8.5.4/7 in the Standard (N3797)
unsigned int ui1 = {-1}; // error: narrows
Given §8.5.4/7 and its 4th bullet point:
A narrowing conversion is an implicit conversion:
- from an integer type or unscoped enumeration type to an integer type that cannot represent all the values of the original type, except where the source is a constant expression whose value after integral promotions will fit into the target type.
I would say there's no narrowing here, as -1 is a constant expression, whose value after integral promotion fits into an unsigned int.
See also §4.5/1 about Integral Promotion:
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.
From 4.13 we have that the rank of -1 (an int) is equal to the rank of an unsigned int, and so it can be converted to an unsigned int.
Edit
Unfortunately Jerry Coffin removed his answer from this thread. I believe he was on the right track, if we accept the fact that the current reading of the 4th bullet point in §8.5.4/7 is wrong, after this change in the Standard.
There is no integral promotion from int
to unsigned int
, therefor it is still illformed.
That would be an integral conversion.
The change in the wording of the standard is intended to confirm the understanding that converting a negative value into an unsigned type is and always has been a narrowing conversion.
Informally, -1 cannot be represented within the range of any unsigned type, and the bit pattern that represents it does not represent the same value if stored in an unsigned int. Therefore this is a narrowing conversion and promotion/widening is not involved.
This is about the dainty art of reading the standard. As usual, the compiler knows best.
Narrowing is an implicit conversion from an integer type to an integer type that cannot represent all the values of the original type
Conversion from integer type int
to integer type unsigned int
, of course, cannot represent all the values of the original type -- the standard is quite unambigious here. If you really need it, you can do
unsigned int ui1 = {-1u};
This works without any errors/warnings since 1u
is a literal of type unsigned int
which is then negated. This is well-defined as [expr.unary.op] in the standard states:
The negative of an unsigned quantity is computed by subtracting its value from 2n, where n is the number of bits in the promoted operand.
-1
however is an int
before and after the negation and hence it becomes a narrowing conversion. There are no negative literals; see this answer for details.
Promotion is, informally, copying the same value into a larger space, so it shouldn't be confused here as the sizes (of signed
and unsigned
) are equal. Even if you try to convert it to some type of larger size, say unsigned long long
it's still a narrowing conversion as it cannot represent a negative number truly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With