How does the casting of primitive datatypes works?
The restriction "primitive datatype" is not enough:
Casting from a 16-bit integer to a 32-bit integer works differently than casting between integer types of the same size. And casting between integer and floating-point types is even more complex.
This Code does work fine. What about this code?
Both code examples will work differently on different CPUs, operating systems and possibly using different compilers.
This is because under some operating systems (e.g. 32-bit Windows)
unsigned data types have the same number of bits; under other operating systems (e.g. 64-bit Windows)
long has twice as many bits as
And you use the
(~n) on a signed data type which may cause different results depending on the compiler you use.
This code indeed prints out negative numbers.
So is there an (architectural) way, to explain this phenomenon?
There are two effects:
The first effect is:
If you pass a value of a wrong data type to some function, C will automatically cast the value.
And if you are casting a value that is outside the range of the data type you are casting to, the result will typically not be what you are intuitively expecting.
In the case of two integer data types, normally the "rightmost" bits of the value are copied to the new value.
(signed char)3478 as an example:
The number 3478 is written as
110110010110 in binary.
signed char is an 8 bit data type. The rightmost 8 bits of
1101 10010110 are
10010110. And the value (-106) is stored as
10010110 in a
signed char variable.
(signed char)3478 will result in (-106).
a is stored in an
unsigned long variable which means that it cannot be negative!
However, you say that you "print out" the value of
a. This means you pass the value to some function that prints it to the screen.
Obviously that function expects some signed data type. C will cast the value stored in
a to the signed data type and as in the example with the number 3478, the result of casting may be a negative number.
If you use
printf you may see a second effect:
If some function (such as
printf) has a variable number of parameters, the way the parameters are passed to the function is depending on the data types passed. (The details may also vary from OS to OS.)
You may now pass the wrong data type to the function; for example you use
signed int) in the
printf format string but you pass an
If you do this, the compiler will write the value of
a to some data storage (memory or register) which is suitable for
unsigned long values before actually calling the function. (For such functions the compiler is not able to find out which data type is really expected by the function, so it has to assume that the function expects the data type you are passing to the function.)
printf will look for a value in some data storage suitable for
signed int values which might be located somewhere completely different. That data storage does not contain any useful value because the compiler wrote the value of
a somewhere else!