How does one safely static_cast between unsigned int and int?

a 夏天 提交于 2019-12-04 01:50:32

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;

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.

You can negate an unsigned twos-complement number by taking the complement and adding one. So let's do that for negatives:

if (val < 0x80000000) // positive values need no conversion
  return val;
if (val == 0x80000000) // Complement-and-addition will overflow, so special case this
  return -0x80000000; // aka INT_MIN
else
  return -(int)(~val + 1);

This assumes that your ints are represented with 32-bit twos-complement representation (or have similar range). It does not rely on any undefined behavior related to signed integer overflow (note that the behavior of unsigned integer overflow is well-defined - although that should not happen here either!).

Note that if your ints are not 32-bit, things get more complex. You may need to use something like ~(~0U >> 1) instead of 0x80000000. Further, if your ints are no twos-complement, you may have overflow issues on certain values (for example, on a ones-complement machine, -0x80000000 cannot be represented in a 32-bit signed integer). However, non-twos-complement machines are very rare today, so this is unlikely to be a problem.

Here's another solution that worked for me:

if (val <= INT_MAX) {
    return static_cast<int>(val);
}
else {
    int ret = static_cast<int>(val & ~INT_MIN);
    return ret | INT_MIN;
}

If I mask off the high bit, I avoid overflow when casting. I can then OR it back safely.

unsigned int u = ~0U;
int s = *reinterpret_cast<int*>(&u); // -1

Сontrariwise:

int s = -1;
unsigned int u = *reinterpret_cast<unsigned int*>(&s); // all ones
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!