1

While reading a book about programmign tricks I saw that -0x80000000 + -0x80000000 = 0. This didn't make sense to me so I wrote a quick C program below to test and indeed the answer is 0:

#include <stdio.h>

int main()
{
    int x = -0x80000000;
    int y = -0x80000000;

    int z = x + y;

    printf("Z is: %d", z);
    return 0;
}

Could anyone shed any light as to why? I saw something about an overflow, but I can't see how an overflow causes 0 rather than an exception or other error. I get no warning or anything.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
Matt
  • 197
  • 10
  • 1
    Yes, it does overflow. No, C does not usually warn or throw exceptions on integer overflows. You see 0 because the lower 32 bits of the actual answer are all 0, and when integer overflow happens, you tend to get the answer modulo 4294967296, that is, modulo 2^32. – Steve Summit Jul 10 '16 at 12:21

2 Answers2

3

What's happening here is signed integer overflow, which is undefined behavior because the exact representation of signed integers is not defined.

In practice however, most machine use 2's complement representation for signed integers, and this particular program exploits that.

0x80000000 is an unsigned integer constant. The - negates it, changing the expression to signed. Assuming int is 32-bit on your system, this value still fits. In fact, it is the smallest value a signed 32-bit int can hold, and the hexadecimal representation of this number happens to be 0x80000000.

When adding numbers in 2's complement representation, it has the feature that you don't need to worry about the sign. They are added exactly the same way as unsigned numbers.

So when we add x and y, we get this:

   0x80000000
+  0x80000000
-------------
  0x100000000

Because an int on your system is 32-bit, only the lowest 32 bits are kept. And the value of those bits is 0.

Again note that this is actually undefined behavior. It works because your machine uses 2's complement representation for signed integers and int is 32-bit. This is common for most machines / compilers, but not all.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • 1
    The type of `0x80000000` is implementation defined. It may be signed. – 2501 Jul 10 '16 at 12:32
  • 2
    Simply negating an unsigned type will not yield a signed type. Under some assumptions, in OP's case the, unsigned value will wrap around back to the (positive) value 0x80000000. – 2501 Jul 10 '16 at 12:46
  • thanks, helped me to understand what is going on. – Matt Jul 10 '16 at 15:00
2

What you're seeing is a lot of implementation defined behavior, very likely triggering undefined behavior at runtime. More than that is not possible to know without details about your and book writers architecture.

The result isn't meaningful without additional information. If you want a definite answer, consult the type ranges for your architecture and make sure the results of assignments and arithmetic fit into their respective types.

2501
  • 25,460
  • 4
  • 47
  • 87