2

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?)

Community
  • 1
  • 1
user1123502
  • 378
  • 3
  • 13
  • Did you mean you can not find anything about unary minus on *signed* 0x80000000? – sth Feb 28 '12 at 00:47
  • Generally the compiler will simply generate an appropriate CPU opcode (such as [x86 `NEG`](http://siyobik.info/main/reference/instruction/NEG)). The standard wording is simply an attempt to formally describe what actually happens. – Greg Hewgill Feb 28 '12 at 00:47
  • @GregHewgill: I think the point of the question is that the C99 standard *doesn't* describe what happens. – Oliver Charlesworth Feb 28 '12 at 00:48
  • 3
    I don't understand what you're asking. Unary - on 0x80000000 is equal to 0x80000000 on most platforms, because 0x100000000 - 0x80000000 = 0x80000000. – Collin Dauphinee Feb 28 '12 at 00:49
  • @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 Feb 28 '12 at 00:51
  • @sth I can not find anything about unary minus on signed 0x80000000 in c++ and both (signed and unsigned) in c. For now, "unsigned & c" part of my question seems to be answered by MSN. – user1123502 Feb 28 '12 at 01:10
  • The latest C99 draft is [n1256.pdf](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf). The latest C11 draft is [n1570.pdf](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf). – Keith Thompson Feb 28 '12 at 01:31

2 Answers2

5

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.

caf
  • 233,326
  • 40
  • 323
  • 462
  • I think int is guaranteed to be at least 32 bits, isn't it? – Collin Dauphinee Feb 28 '12 at 00:56
  • @dauphic: No, `int` is guaranteed to be at least 16 bits, `long` is guaranteed to be at least 32 bits and `long long` is guaranteed to be at least 64 bits. To round it out, `char` is guaranteed to be at least 8 bits and `short` is guaranteed to be at least 16 bits. – caf Feb 28 '12 at 00:59
  • Note that POSIX requires `int` to be at least 32 bits. – R.. GitHub STOP HELPING ICE Feb 28 '12 at 01:02
  • @caf Sure. Suppose unsigned int is 32 bit wide. I still interested on unary minus on signed int 0x80000000 in c++. – user1123502 Feb 28 '12 at 01:13
  • @user1123502: As per the table in my question, if `unsigned int` is 32 bits wide then the result of `-0x80000000` is `0x100000000 - 0x80000000`, which is `0x80000000`. – caf Feb 28 '12 at 03:41
  • @caf That is nice. But what about **signed** int? – user1123502 Feb 28 '12 at 03:55
  • @user1123502: If you have a 32 bit `int` then the type of the hexadecimal constant `0x80000000` is still `unsigned int`, so the result is the same. – caf Feb 28 '12 at 03:57
  • @caf I used imprecise wording. What I mean is like `int a = INT_MIN; int b=-a;`. More elaborated question is http://stackoverflow.com/questions/9476036/c-only-unary-minus-for-0x80000000 In the future, I shall try not to ask "multipart" or "compound" questions. – user1123502 Feb 28 '12 at 04:12
  • 1
    @user1123502: If `-INT_MIN` is not representable (as on two's complement implementations), then the behaviour is undefined as per C99 §6.5 Expressions p5. You won't often see a crash in practice, but you often will for other, similar expressions like `INT_MIN / -1`. – caf Feb 28 '12 at 04:23
2

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.

MSN
  • 53,214
  • 7
  • 75
  • 105
  • 1
    You are making an assumption about the maximum value that can be represented in the type of the constant `0x80000000`. – caf Feb 28 '12 at 00:54
  • @caf, ah, yes. Well, you'll get the answer anyway. – MSN Feb 28 '12 at 03:17