Home > OS >  Is (int)(unsigned)-1 == -1 undefined behavior
Is (int)(unsigned)-1 == -1 undefined behavior

Time:01-21

I am trying to understand the meaning of the statement:

(int)(unsigned)-1 == -1;

To my current understanding the following things happen:

  1. -1 is a signed int and is casted to unsigned int. The result of this is that due to wrap-around behavior we get the maximum value that can be represented by the unsigned type.

  2. Next, this unsigned type maximum value that we got in step 1, is now casted to signed int. But note that this maximum value is an unsigned type. So this is out of range of the signed type. And since signed integer overflow is undefined behavior, the program will result in undefined behavior.

My questions are:

  1. Is my above explanation correct? If not, then what is actually happening.
  2. Is this undefined behavior as i suspected or implementation defined behavior.

PS: I know that if it is undefined behavior(as opposed to implementation defined) then we cannot rely on the output of the program. So we cannot say whether we will always get true or false.

CodePudding user response:

Cast to unsigned int wraps around, this part is legal.

Out-of-range cast to int is legal starting from C 20, and was implementation-defined before (but worked correctly in practice anyway). There's no UB here.

The two casts cancel each other out (again, guaranteed in C 20, implementation-defined before, but worked in practice anyway).

Signed overflow is normally UB, yes, but that only applies to overflow caused by a computation. Overflow caused by a conversion is different.

cppreference

If the destination type is signed, the value does not change if the source integer can be represented in the destination type. Otherwise the result is:

(until C 20) implementation-defined

(since C 20) the unique value of the destination type equal to the source value modulo 2n where n is the number of bits used to represent the destination type.

(Note that this is different from signed integer arithmetic overflow, which is undefined).


More specifics on how the conversions work.

Lets's say int and unsigned int occupy N bits.

The values that are representable by both int and unsigned int are unchanged by the conversion. All other values are increased or decreased by 2N to fit into the range.

This conveniently doesn't change the binary representation of the values.

E.g. int -1 corresponds to unsigned int 2N-1 (largest unsigned int value), and both are represented as 11...11 in binary. Similarly, int -2N-1 (smallest int value) corresponds to unsigned int 2N-1 (largest int value 1).

int:   [-2^(n-1)] ... [-1] [0] [1] ... [2^(n-1)-1]
            |           |   |   |           |
            |           '---|---|-----------|-----------------------.
            |               |   |           |                       |
            '---------------|---|-----------|----------.            |
                            |   |           |          |            |
                            V   V           V          V            V
unsigned int:              [0] [1] ... [2^(n-1)-1] [2^(n-1)] ... [2^n-1]

CodePudding user response:

Edit: Versions prior to C 20 do not require two's complement

It might help understanding the binary representation of -1 which is: 0b1111'1111'1111'1111'1111'1111'1111'1111. I should note, that this is a 4-byte representation of -1. Different machines might represent int differently.

You are casting to unsigned and then back to int which changes how you interpret the 1's and 0's. In decimal (or sometimes called denary), what you're doing is the equivalent of casting it to 4294967295 and then back to -1.

The type of the integer literal is the first type in which the value can fit, from the list of types which depends on which numeric base and which integer-suffix was used

Because -1 fits into int, that is how it's interpreted. See: https://en.cppreference.com/w/cpp/language/integer_literal

this is out of range of the signed type. And since signed integer overflow

This is not integer overflow. This is binary representation. Integer overflow would be:

    int int_max = 2147483647; // this is the maximum integer int on my machine
    int one = 1;             
    
    int overflow = x   s;         // sum is equal to -2147483648

The above is an example integer overflow because the maximum representation

  •  Tags:  
  • Related