I'm working in a code skeleton that has a lot of preexisting code using the regular old int
type in C. However, the code I need to write requires that I use a fixed length int32_t
. However, I need to be able to take input from the regular code in terms of int
, and output to variables that are also just regular int
. Does casting from int32_t
to int
preserve the value of the variable, or the specific data representation of it (in which case I may need to bitshift in order to preserve the value). Conversely, does casting from int
to int32_t
introduce any complications? Any answer would be greatly appreciated, but especially any that generally and specifically explain the casting conventions of the stdint
library.
How does casting between Cs default
int
type and <stdint.h>'sintXX_t
types work?
When intXX_t
and int
same size, range and effective type, no "work" really happens.
When intXX_t
has wider range than int
, all values are preserved in the new type. The upper bits are a sign extension.
When intXX_t
has narrower range than int
, out of range values are converted in an implementation defined way. This is very commonly a mod like wrap around (lower bits are the same)
When intXX_t
has same range as int
, the types may differ, but usually are the same. In select code (as with _Generic
), the difference is important.
int
comes in various sizes and encoding.
32-bit (2's complement): This is quite common, especially on desktop computers.
16-bit (2's complement): This is common in small embedded processors.
Other: including Non-2's complement, 64-bit on some 64-bit graphics processors, some non-power-of-2 on old or esoteric machines. For OP's concerns, simply know others exists, but it is very unlikely OP needs to port code to or from such machines.
Does casting from
int32_t
toint
preserve the value of the variable, or the specific data representation of it (in which case I may need to bitshift in order to preserve the value).
Bit shifting not needed.
32-bit (2's complement): Casting int32_t
to int
does not lose any value information. In select situations, a type change may happen. int32_t
may have been type def'd as a long
, yet far more likely int32_t, int
are exactly the same type.
16-bit (2's complement): Casting int32_t
to int
loses info as the the range is much smaller. On such machines, better to cast int32_t
to long
.
Conversely, does casting from
int
toint32_t
introduce any complications?
32-bit (2's complement): Very unlikely any problem.
16-bit (2's complement): Some situations deserve review as int32_t
is wider and takes up more space.
Well written code is less likely to cause issues, yet much code does not consider portability.
For OP's case, I recommend to create macros, rather than direct casting. This will facilitate tracking the change to your code base due to the new work requirement. Further, alternatives could then readily be used to debug range reduction/increase issues.
// Use names per your coding style
#define inttoint32(i) ((int32_t) (i))
#define int32toint(i32) ((int) (i32))