8

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.

Community
  • 1
  • 1
Wake up Brazil
  • 3,421
  • 12
  • 19
  • No. It is a integer already (a signed integer), after conversion it's value does not fit into the target type. An `unisgned integer` cannot represent all the values of a `signed integer`, specifically; it cannot represent a negative value. – Elliott Frisch Jan 20 '14 at 19:08
  • 1
    "-1 is a constant expression, whose value after integral promotion fits into an unsigned int." - no, -1 is of type `int`, and as such, it's not promoted to anything. –  Jan 20 '14 at 19:12
  • @ElliottFrisch If you view an unsigned integer as a positive integer is can't, if you view as a modular integer it can!! – curiousguy Aug 27 '15 at 19:49

3 Answers3

7

There is no integral promotion from int to unsigned int, therefor it is still illformed.

That would be an integral conversion.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
1

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.

Community
  • 1
  • 1
legends2k
  • 31,634
  • 25
  • 118
  • 222
  • I think a compiler could legitimately emit a warning for -1u. – david.pfx Jan 21 '14 at 14:07
  • 1
    That's interesting. So `int` to `unsigned int` is narrowing, and by the same definition, `unsigned int` to `int` is also narrowing? – Ben Hymers Jan 21 '14 at 14:12
  • 1
    Yes, for `unsigned x = 0u; signed y = {x};` GCC (4.8.1) spits: _warning: narrowing conversion of 'x' from 'unsigned int' to 'int' inside { }_. – legends2k Jan 21 '14 at 14:17
1

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.

david.pfx
  • 10,520
  • 3
  • 30
  • 63
  • `Therefore this is a narrowing conversion and promotion/widening is not involved.` Where does it say in the Standard that an integral promotion doesn't apply in this case? By the contrary, the bullet point I highlighted in my question mentions specifically the term `integral promotion`. – Wake up Brazil Jan 21 '14 at 16:45
  • @Wake: S6.3.1.1 defines integer promotions. They only apply to a value of lower rank, or a bit field, and they preserve sign. They __never__ operate to convert a signed integer into unsigned. Other references to integer promotions do not change this definition. – david.pfx Jan 22 '14 at 14:08
  • I don't know of any 6.3.1.1 or S6.3.1.1 in the drafts N3337 and N3797. Integral promotion is defined in §4.5 in both drafts and the paragraph that I alluded in my question is the very first paragraph in this section of the Standard. According to this paragraph, definitely, -1 can be promoted to an unsigned int. And this occurs because the rank of an int is equal to the rank of an unsigned int (from §4.13). – Wake up Brazil Jan 22 '14 at 16:46
  • Oops. Sorry, I was in the C standard there. Does not change the situation. I think you are reading the 'otherwise' in S4.5 as if it applied to every integer type and it does not. It only applies to the last if, the bit about representing all the values. Since int is not 'less than the rank of int', nothing in that para applies to int. In short, int is never promoted. – david.pfx Jan 23 '14 at 13:58
  • (+1) You nailed it! Excellent answer. Tks – Wake up Brazil Jan 23 '14 at 23:12