2
votes

The n3337.pdf draft, 5.3.1.8, states that:

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ⁿ, where n is the number of bits in the promoted operand. The type of the result is the type of the promoted operand.

For some cases it is enough. Suppose unsigned int is 32 bits wide, then (-(0x80000000u)) == 0x80000000u, isn't it?

Still, I can not find anything about unary minus on unsigned 0x80000000. Also, C99 standard draft n1336.pdf, 6.5.3.3 seems to say nothing about it:

The result of the unary - operator is the negative of its (promoted) operand. The integer promotions are performed on the operand, and the result has the promoted type.

UPDATE2: Let us suppose that unsigned int is 32 bits wide. So, the question is: what about unary minus in C (signed and unsigned), and unary minus in C++ (signed only)?

UPDATE1: both run-time behavior and compile-time behavior (i.e. constant-folding) are interesting.

(related: Why is abs(0x80000000) == 0x80000000?)

2
Did you mean you can not find anything about unary minus on signed 0x80000000?sth
Generally the compiler will simply generate an appropriate CPU opcode (such as x86 NEG). The standard wording is simply an attempt to formally describe what actually happens.Greg Hewgill
@GregHewgill: I think the point of the question is that the C99 standard doesn't describe what happens.Oliver Charlesworth
I don't understand what you're asking. Unary - on 0x80000000 is equal to 0x80000000 on most platforms, because 0x100000000 - 0x80000000 = 0x80000000.Collin Dauphinee
@sth c99 standard seems to say nothing at all about corner case, that is: 6.5.3.3.3: The result of the unary - operator is the negative of its (promoted) operand. The integer promotions are performed on the operand, and the result has the promoted type.user1123502

2 Answers

5
votes

For your question, the important part of the quote you've included is this:

The negative of an unsigned quantity is computed by subtracting its value from 2ⁿ, where n is the number of bits in the promoted operand.

So, to know what the value of -0x80000000u is, we need to know n, the number of bits in the type of 0x80000000u. This is at least 32, but this is all we know (without further information about the sizes of types in your implementation). Given some values of n, we can calculate what the result will be:

n   | -0x80000000u 
----+--------------
32  | 0x80000000
33  | 0x180000000
34  | 0x380000000
48  | 0xFFFF80000000
64  | 0xFFFFFFFF80000000

(For example, an implementation where unsigned int is 16 bits and unsigned long is 64 bits would have an n of 64).


C99 has equivalent wording hidden away in §6.2.5 Types p9:

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.

The result of the unary - operator on an unsigned operand other than zero will always be caught by this rule.

With a 32 bit int, the type of 0x80000000 will be unsigned int, regardless of the lack of a u suffix, so the result will still be the value 0x80000000 with type unsigned int.

If instead you use the decimal constant 2147483648, it will have type long and the calculation will be signed. The result will be the value -2147483648 with type long.

2
votes

In n1336, 6.3.1.3 Signed and Unsigned Integers, paragraph 2 defines the conversion to an unsigned integer:

Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.

So for 32-bit unsigned int, -0x80000000u==-0x80000000 + 0x100000000==0x80000000u.