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?
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