Quoting the C++03 standard, §4.7/3 (Integral Conversions):
If the destination type is signed, the value is unchanged if it can be represented in the destination type (and bit-field width); otherwise, the value is implementation-defined.
Because the result is implementation-defined, by definition it is impossible for there to be a truly portable solution.
Answer from ildjarn on Stack OverflowQuoting the C++03 standard, §4.7/3 (Integral Conversions):
If the destination type is signed, the value is unchanged if it can be represented in the destination type (and bit-field width); otherwise, the value is implementation-defined.
Because the result is implementation-defined, by definition it is impossible for there to be a truly portable solution.
While there are ways to do this using casts and conversions, most rely on undefined behavior that happen to have well-defined behaviors on some machines / with some compilers. Instead of relying on undefined behavior, copy the data:
int signed_val;
std::memcpy (&signed_val, &val, sizeof(int));
return signed_val;
Unsigned int to int and vice-versa - C++ Forum
static_cast<unsigned> - Post.Byes - Bytes
[C++] static_cast'ing a negative value to an unsigned int
Static cast from unsigned int64 to int could be problematic
Would these asserts now always be true?
#include <cstdint>
#include <cassert>
#include <limits>
int main()
{
{
int64_t i1 = std::numeric_limits<int64_t>::max();
uint64_t u = static_cast<uint64_t>(i1);
int64_t i2 = static_cast<int64_t>(u);
assert(i1 == i2);
}
{
uint64_t u1 = std::numeric_limits<uint64_t>::max();
int64_t i = static_cast<int64_t>(u1);
uint64_t u2 = static_cast<uint64_t>(i);
assert(u1 == u2);
}
return 0;
}Based on the implementation of "Signed Integers are Two's Complement" (P1236R1/P0907R4) by the compiler
I am currently working on a project to manipulate ppm files which contain unsigned char in the fourth line if code that represent the rgb values and I don't know how to translate them into integers so I can match them to their rgb values.
You can static_cast from an int to an unsigned, which performs the appropriate conversion. But what you have is a pointer; this pointer points to a region of memory that is to be interpreted as an int. Dereferencing the pointer yields the int's value. static_cast will not convert between pointers to unrelated types.
int i = 0;
int* ip = &i;
int j = *ip; // treat the region pointed to as an int
To treat the memory as unsigned under dereference, you need to reinterpret the memory; that's what reinterpret_cast does.
int i = 0;
int* ip = &i;
unsigned j = *reinterpret_cast<unsigned*>(ip); // treat the region pointed to as unsigned
You shouldn't do this, however. reinterpret_cast does exactly what it says: reinterprets the memory as a different type. If the bit pattern doesn't match what would be expected for that type, the result will differ from the conversion performed by static_cast<unsigned>. This can be the case on a system where signed integers are not represented using 2's complement, for instance.
The correct approach is to dereference the int* then static_cast<unsigned> the result of that:
int i = 0;
int* ip = &i;
unsigned j = static_cast<unsigned>(*ip); // treat the region pointed to as int
// then convert the int to unsigned
To summarise: static_cast will perform the integer conversion, but it won't re-interpret a memory region as a different type. That's what reinterpret_cast is for.
You would have to use:
unsigned *j = static_cast<unsigned*>(static_cast<void*>(&i));
this is what you can read here at point 5, or simply use: reinterpret_cast:
int i = 0;
unsigned *j = reinterpret_cast<unsigned*>(&i);
often instead of using cast-s programmers use unions as below:
union {
int n;
unsigned char bt[4];
} data;
data.n = i;
data.bt[3] = 0xff;
As it was said in comments, using union for casting is undefined behaviour - even if it is supported by most compilers : you can read more on this here: Is using an union in place of a cast well defined? and here Is using an union in place of a cast well defined?