/* [1] */
int i = -1;
unsigned u = (unsigned)i;
↑ This is guaranteed to not work on a sign-and-magnitude or 1's complement machine, because conversion to unsigned is guaranteed to yield the signed value modulo 2n where n is the number of value representation bits in the unsigned type. I.e. the conversion is guaranteed to yield the same result as if the signed type used two's complement representation.
/* [2] */
int i = -1;
unsigned u;
memcpy(&u, &i, sizeof i);
↑ This would work nicely, because the types are guaranteed to have the same size.
/* [3] */
int i = -1;
unsigned u = *(unsigned *)&i;
↑ This is formally Undefined Behavior in C++11 and earlier, but it's one of the cases included in the "strict aliasing" clause in the standard, and so it's probably supported by every extant compiler. Also, it's an example of what reinterpret_cast
is there for. And in C++14 and later the language about undefined behavior has been removed from (1)the section on lvalue to rvalue conversion.
If I did this I would use the named C++ cast for clarity.
I would however try out what the sometimes look-the-standard-allows-me-to-do-the-impractical-thing compilers have to say about it, in particular g++ with its strict aliasing option, whatever it is, but also clang, since it's designed as a drop-in replacement for g++.
At least if I planned on the code being used with those compilers and options.
1) [conv.lval], §4.1/1 in both C++11 and C++14.