13

From the standard (4.7) it looks like the conversion from int to unsigned int, when they both use the same number of bits, is purely conceptual:

If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2 n where n is the number of bits used to represent the unsigned type). [ Note: In a two’s complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation). — end note ]

So in this direction the conversion preserves the bitmask. I am not sure the standard guarantees the same for the conversion from unsigned int to int (again, assuming the same number of bits are used). The standard here says:

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

What does it exactly mean "the destination type" here? For instance 2^32-1 cannot be represented by a 32 bit int. Does that mean that it cannot be represented in the destination type and therefore it cannot be assumed that the bit pattern will stay the same?

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
stefano
  • 579
  • 5
  • 12
  • in theory you could be one a ones complement system and the bit pattern could change. This would be something outside the C++ standard. Pratically though, are there any non twos complement systems anymore? – Doug T. Feb 02 '13 at 18:25
  • 3
    See also http://stackoverflow.com/questions/13150449/ – Nemo Feb 02 '13 at 21:09

3 Answers3

4

You cannot assume anything.

The first quote doesn't state that the bitmask remains the same. It may be the same in two's complement, but not in one's complement or other representations.

Second, implementation-defined means implementation-defined, you can't assume anything in general.

In theory, the representation can be completely different after each conversion. That's it.


If you look at it in a realistic way things come more concrete. Usually, int's are stored in two's complement and signed->unsigned preserves the pattern as unsigned->signed does (since the value can be implementation-defined, the cheapest way is doing nothing).

ipc
  • 8,045
  • 29
  • 33
  • 1
    (Assuming twos complement notation) The first quote does state that the bitmask remains the same. It says, in fact, exactly that. `Note: In a two’s complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation).` In other words, if you cast to an unsigned integral type of the same size, the bit pattern will be exactly the same. – Wug Jun 21 '13 at 20:21
3

int is the destination type in this case. As you say 2^32-1 cannot be represented so in this case so it is implementation-specific. Although, I've only ever seen it preserve bit patterns.

EDIT: I should add that in the embedded world often whats done when one storage location needs multiple representations that are bit-for-bit identical we often use unions.

so in this case

union FOO {
    int32_t signedVal;
    uint32_t unsignedVal;
} var;

var can be accessed as var.signedVal to get the 32 bits stored as a signed int and var.unsignedVal to get the 32 bits stored as an unsigned value. In this case bits will be preserved.

David G
  • 94,763
  • 41
  • 167
  • 253
user1816847
  • 1,877
  • 3
  • 17
  • 29
1

"Destination type" refers to the type you're assigning/casting to.

The whole paragraph means a 32 bit unsigned int converted to a 32 bit signed int will stay as-is, given the value fits into the signed int. If they don't fit, it depends on the implementation on what it does (e.g. truncate). That means it really depends on the implementation whether the bits stay or whether they're changed (there's no guarantee).

Or in other words: If the unsigned int uses its most significant bit, the result is no longer predictable. Otherwise there's no change (other than changing the "name on the box").

Mario
  • 35,726
  • 5
  • 62
  • 78
  • I believe the above analysis assumes that there are no padding bits and that the value bits are in the same positions. – Raymond Chen Feb 02 '13 at 18:33
  • I'd say it doesn't change anything (as long as you assume there are the same padding bits for both types). If that's not true, you're essentially looking at different lengths anyway (unless I misunderstood you). – Mario Feb 02 '13 at 18:35