How does one safely static_cast between unsigned int and int?

后端 未结 6 1281
猫巷女王i
猫巷女王i 2021-02-19 19:36

I have an 8-character string representing a hexadecimal number and I need to convert it to an int. This conversion has to preserve the bit pattern for

相关标签:
6条回答
  • 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;
    
    0 讨论(0)
  • 2021-02-19 19:56

    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.

    0 讨论(0)
  • 2021-02-19 20:04

    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.

    0 讨论(0)
  • 2021-02-19 20:06

    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.

    0 讨论(0)
  • 2021-02-19 20:12
    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
    
    0 讨论(0)
  • 2021-02-19 20:15

    C++20 will have std::bit_cast that copies bits verbatim:

    #include <bit>
    #include <cassert>
    #include <iostream>
    
    int main()
    {
        int i = -42;
        auto u = std::bit_cast<unsigned>(i);
        // Prints 4294967254 on two's compliment platforms where int is 32 bits
        std::cout << u << "\n";
    
        auto roundtripped = std::bit_cast<int>(u);
        assert(roundtripped == i);
        std::cout << roundtripped << "\n"; // Prints -42
    
        return 0;
    }
    

    cppreference shows an example of how one can implement their own bit_cast in terms of memcpy (under Notes).

    While OpenVMS is not likely to gain C++20 support anytime soon, I hope this answer helps someone arriving at the same question via internet search.

    0 讨论(0)
提交回复
热议问题