How can I best convert a uint32_t
to an int32_t
quickly with wrapping, in C++?
Some tries:
uint32_t y = UINT32_MAX;
int32_t x = (int32_t)y; // UB on overflow
int32_t x = *(int32_t*)&y; // does this violate strict aliasing?
Widening conversions (promotion) Because widening conversions are always safe, the compiler performs them silently and doesn't issue warnings. The following conversions are widening conversions.
uint32_t is a numeric type that guarantees 32 bits. The value is unsigned, meaning that the range of values goes from 0 to 232 - 1. This. uint32_t* ptr; declares a pointer of type uint32_t* , but the pointer is uninitialized, that is, the pointer does not point to anywhere in particular.
And the reason why people use uint32_t rather than the other types is because they usually don't have such hardware to do testing on. (The same is true of int32_t to a lesser extent, and even int and short ). An example of the corner case: Let unsigned short == uint32_t and int == int48_t .
The uint_fast*_t type simply defines the fastest type for representing a given number of bits. Think about it this way: you define a variable of type short and use it several times in the program, which is totally valid. However, the system you're working on might work more quickly with values of type int .
int32_t x = (int32_t)y;
is not overflow and not UB. Overflow is when an arithmetic operation produces a result outside the range of representable values. However, a conversion is not an arithmetic operation.
This situation is implementation-defined behaviour. All implementations that I'm aware of define the behaviour as making no change in the representation.
Note that no cast is necessary here. You can write int32_t x = y;
.
In practical terms, this is simpler and will always work. So much code relies on this that no vendor is ever going to define any other behaviour (not that they have any reason to do so anyway).
int32_t x = *(int32_t*)&y
is not UB. It does not violate strict aliasing because the signed version of a type is allowed to alias the unsigned version. This code is guaranteed to produce the int32_t
with the same representation as the corresponding uint32_t
(i.e. "wrapping", since these types are guaranteed to be 2's complement).
union {
int32_t i;
uint32_t u;
} u;
u.i = ...;
printf("%" PRIu32 "\n", u.u);
This and memcpy(&uint_var, &int_var, sizeof uint_var)
are the two standard ways to do such a conversion without invoking undefined behavior.
See also:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With