1

Possible Duplicate:
Signed to unsigned conversion in C - is it always safe?

How can uint64_t store a negative number? - isn't it meant to be unsigned or is my code dangerous and it's working by fluke?

In the code I assign a negative number to uint64_t uint64_neg ( i expect the negativeness, the sign to be lost) then assign the uint64_t to a int64_t but the negativeness is still there - why does this work please ?

uint64_t uint64_neg = -150;

int64_t int64_neg = uint64_neg;

Thanks a lot.

Community
  • 1
  • 1
CodingHero
  • 2,865
  • 6
  • 29
  • 42

2 Answers2

4

Section 4.7 paragraph 3 in the standard says (with my emphasis added):

If the destination type is signed, the value is unchanged if it can be represented in the destination type (andbit-field width); otherwise, the value is implementation-defined.

That is, on your compiler, an unsigned to signed conversion just "copies the bits", leaving some implementation defined value in that unsigned int. This overflows the value of the signed int when copying back over, which happens to be implementation defined on your platform to go back to the same signed number.

The standard does not guarantee any of that behavior.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
0

Bits are bits. An implicit conversion is occuring. Any unsigned int can be represented as a signed int so long as they are the same size. I was confused when I first saw this too (it's not very common for many types of programming) and may differ from compiler to compiler so test it before relying on it. Here's some code that demonstrates how it works using chars to make it simple to understand:

#include <iostream>

int main()
{
    unsigned int u = 0;

    while ( u != 256 )
    {
       const signed char s = u;  // putting an unsigned type (u) into a signed type (s)

       // cast s up here so we don't print the extended ascii char.
       std::cout << (signed int)s << " signed == " << u << " unsigned" << std::endl;
       ++u;
    }

    return 0;
}

Here's a bit of output from that code:

-128 signed == 128 unsigned
-127 signed == 129 unsigned
-126 signed == 130 unsigned
...
-3 signed == 253 unsigned
-2 signed == 254 unsigned
-1 signed == 255 unsigned

C++11 compilers will generate a narrowing error if you initialize this way:

unsigned int j = {-32768}; // Notice the brackets
01100110
  • 2,294
  • 3
  • 23
  • 32