Search code examples
cintegertwos-complement

C How does signed to signed integer conversion work?


How does the computer convert between differently sized signed intgers?

For example when i convert the long long int value 12000000000 to int how does it reduce the value? And how does it handle negative numbers?


Solution

  • how does it reduce the value?

    From C11 standard 6.3.1.3p3:

    When a value with integer type is converted to another integer type [...]

    [...]

    Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.

    It is not defined how to convert the value - instead, each compiler may have different behavior, but it has to have some documented behavior. Nowadays we live in twos-complement world - it's everywhere the same. Let's take a look at gcc compiler - from ex. gcc documentation integers implementation-defined behavior:

    • The result of, or the signal raised by, converting an integer to a signed integer type when the value cannot be represented in an object of that type (C90 6.2.1.2, C99 and C11 6.3.1.3).

    For conversion to a type of width N, the value is reduced modulo 2^N to be within range of the type; no signal is raised.

    So we have:

    long long int value 12000000000 to int

    Let's assume long long int has 64 bits and int has 32 bits and byte has 8 bits and we use twos-complement, so INT_MIN = -2147483648 INT_MAX = 2147483647 and N is 32, and 2^N is, well, 4294967296. You should take a peek at modular arithmetic and we know that:

    12000000000 = 3 * 4294967296 + -884901888
    

    So it will be converted to -884901888. That is irrelevant to what format is used to store the number - it can be in any format it wishes.

    Now, gcc is smart, and while the documentation states the mathematical description of the algorithm in modulo arithmetic, you can note that:

    $ printf("%16llx\n%16x\n", 12000000000ll, (int)12000000000ll);
           2cb417800
            cb417800
    

    Ie the mathematical operation of "modulo 2^32" is equal in binary to doing an AND mask with all bits set num & 0xffffffff.

    And how does it handle negative numbers?

    Exactly the same way, there's just a minus. For example -12000000000ll :

    -12000000000ll = -3 * 4294967296 + 884901888 
    

    So (int)-12000000000ll will be converted to 884901888. Note that in binary it's just:

    $ printf("%16llx\n%16x\n", -12000000000ll, (int)-12000000000ll);'
    fffffffd34be8800
            34be8800