It is worth noting that unsigned overflow is guaranteed to be defined as 2's complement (wrapping) overflow, at least by Clang and other commonly available C compilers.
This is actually guaranteed by the standard (although the language used is not "2s complement", but "repeatedly adding or subtracting one more than the maximum value that can be stored in the type until the value is in range").
C requires that these sorts of type conversions happen through unions: using pointer casts is not correct and undefined behavior results.
Actually, loading a member of a union other than the one most recently stored to is undefined behaviour too - it's just that using a union in this way falls into the "...both Clang and GCC nail down a few behaviors that the C standard leaves undefined." category. (And most other compilers besides - there is much historical usage of this).
This is actually guaranteed by the standard (although the language used is not "2s complement", but "repeatedly adding or subtracting one more than the maximum value that can be stored in the type until the value is in range").
C requires that these sorts of type conversions happen through unions: using pointer casts is not correct and undefined behavior results.
Actually, loading a member of a union other than the one most recently stored to is undefined behaviour too - it's just that using a union in this way falls into the "...both Clang and GCC nail down a few behaviors that the C standard leaves undefined." category. (And most other compilers besides - there is much historical usage of this).