Given
int32_t x;then
x = ((uint32_t)x) >> 5;is exactly equivalent to
x >>= 5; x &= 0x07FFFFFF;based on standard C, no implementation-defined behaviour or differences between compilers, as long as they follow standard C (currently C99, C11, C17, or C2x/C23).
(Remember, exact-width integer types
uintN_t and
intN_t always use two's complement representation for negative values with all possible bit patterns corresponding to ordinary values, no padding, no trap representations.)
does a cast back to int change any bits (for any value of x)?
In the right shift case (by a positive, nonzero number of bits) that is not relevant, because the result is always positive, because the sign bit is the most significant bit and a zero will be shifted in when using the unsigned type cast. That is, if the exact-size (
uint_N) cast value is shifted right by at least one bit, then the result is guaranteed to fit and be within the range of the corresponding
intN_t type, and the standard says that in that case that will be the resulting value.
The standard leaves a cast from unsigned to signed integer types
implementation defined only when the value cannot be represented in the signed type. GCC will never change the bit pattern (see
here), and will simply re-interpret the sign bit as-is. This is another implementation-defined behaviour one can expect, and note in the documentation for portable code. For example,
(int32_t)(0x80000008u) == -2147483640.
I did some digging for Clang, but I couldn't find a similar implementation behaviour list, but I
believe it behaves the exact same way. It is actually quite possible that future C standards end up codifying this, because I personally have never used a C99-or-later compliant compiler that behaved differently.