## Question:

The language standard repeatedly mentions that operations on unsigned integers are performed modulo `2^n`

, where `n`

is the number of bits involved in representing the value of the unsigned integer.

Let's have this code:

```
unsigned char a = 1;
a = -a;
```

And, let `unsigned char`

be eight bits, and `int`

sixteen bits.

I already thought that the expression `-a`

either immediately converts to an `unsigned char`

value equal to `255`

; or `a`

is expanded to an `int`

, then that `int`

becomes `-1`

, and finally `-1`

is converted to an `unsigned char`

value of `255`

. However, as it turned out, the standard specifies a special, rather strange way to calculate the unary minus for unsigned values.

Here is a quote from paragraph 8.3.1/8 of that document:

The operand of the unary – operator shall have arithmetic or unscoped enumeration type and the result is the negation of its operand. Integral promotion is performed on integral or enumeration operands. The negative of an unsigned quantity is computed by subtracting its value from

`2^n`

, where`n`

is the number of bits in thepromotedoperand. The type of the result is the type of the promoted operand.

If I understood correctly what was written, then the value of the expression `-a`

in the above example is equal to the value `2^n - 1`

, where `n`

is equal to the number of bits in **the extended** operand. Those. `2^n - 1 == 2^16 - 1 == 65536 - 1 == 65535`

. But the given value cannot be represented in a sixteen-bit `int`

, which means that attempting to evaluate `-a`

results in undefined behavior.

The question is: can a unary minus "work" as written above? And if so, why does the standard define such strange behavior of unary minus for unsigned values?

It is also strange that if you write like this:

```
unsigned char a = 1;
a = 0 - a;
```

then it doesn't seem to lead to undefined behavior. Since `0`

is of type `int`

, `a`

will be expanded to `int`

, the difference `0-1`

will be computed, and the resulting `int`

value will be safely truncated modulo `256`

to `255`

.

## Answer:

The words about 2 ^{n} apply only to unsigned types (arithmetic modulo `max() + 1`

– the result is always defined). These words do not refer to the int type.

If all `unsigned char`

values of type fit into `int`

(often happens), then (C++ n4659 §7.6.1):

```
-(unsigned char)1 = (integer promotion, likely) = -(int)1 = (int)-1
```

If they do not fit, then:

```
-(unsigned char)1 = (integer promotion, rare) = -(unsigned int)1
= (unsigned int)2**n-1 = (by definition) = (unsigned int)UINT_MAX
```

where `n`

is the number of bits for the values (value bits – may be different from `sizeof * CHAR_BIT`

if there are padding bits – C n1570 §6.2.6.2.1).

That is, the type `-a`

of the expression is int or unsigned int. To assign back to `a`

requires (possibly a narrowing conversion) to unsigned char:

```
(int)-1 = (UCHAR_MAX + 1) - 1 = (unsigned char)UCHAR_MAX
```

or:

```
(unsigned int)UINT_MAX = UINT_MAX % (UCHAR_MAX + 1) = (unsigned char)UCHAR_MAX
```

i.e. the value is always obtained in this case 2 ^{CHAR_BIT} -1 :

```
a == std::numeric_limits<unsigned char>::max()
```