Convert unsigned int to signed int C

后端 未结 9 2084
忘掉有多难
忘掉有多难 2020-12-05 14:31

I am trying to convert 65529 from an unsigned int to a signed int. I tried doing a cast like this:

unsigned int x = 65         


        
相关标签:
9条回答
  • 2020-12-05 14:43

    You are expecting that your int type is 16 bit wide, in which case you'd indeed get a negative value. But most likely it's 32 bits wide, so a signed int can represent 65529 just fine. You can check this by printing sizeof(int).

    0 讨论(0)
  • 2020-12-05 14:47

    @Mysticial got it. A short is usually 16-bit and will illustrate the answer:

    int main()  
    {
        unsigned int x = 65529;
        int y = (int) x;
        printf("%d\n", y);
    
        unsigned short z = 65529;
        short zz = (short)z;
        printf("%d\n", zz);
    }
    
    65529
    -7
    Press any key to continue . . .
    


    A little more detail. It's all about how signed numbers are stored in memory. Do a search for twos-complement notation for more detail, but here are the basics.

    So let's look at 65529 decimal. It can be represented as FFF9h in hexadecimal. We can also represent that in binary as:

    11111111 11111001

    When we declare short zz = 65529;, the compiler interprets 65529 as a signed value. In twos-complement notation, the top bit signifies whether a signed value is positive or negative. In this case, you can see the top bit is a 1, so it is treated as a negative number. That's why it prints out -7.

    For an unsigned short, we don't care about sign since it's unsigned. So when we print it out using %d, we use all 16 bits, so it's interpreted as 65529.

    0 讨论(0)
  • 2020-12-05 14:50

    I know this is an old question, but I think the responders may have misinterpreted it. I think what was intended was to convert a 16-digit bit sequence received as an unsigned integer (technically, an unsigned short) into a signed integer. This might happen (it recently did to me) when you need to convert something received from a network from network byte order to host byte order. In that case, use a union:

    unsigned short value_from_network;
    unsigned short host_val = ntohs(value_from_network);
    // Now suppose host_val is 65529.
    union SignedUnsigned {
      short          s_int;
      unsigned short us_int;
    };
    SignedUnsigned su;
    su.us_int = host_val;
    short minus_seven = su.s_int;
    

    And now minus_seven has the value -7.

    0 讨论(0)
  • 2020-12-05 14:58

    It seems like you are expecting int and unsigned int to be a 16-bit integer. That's apparently not the case. Most likely, it's a 32-bit integer - which is large enough to avoid the wrap-around that you're expecting.

    Note that there is no fully C-compliant way to do this because casting between signed/unsigned for values out of range is implementation-defined. But this will still work in most cases:

    unsigned int x = 65529;
    int y = (short) x;      //  If short is a 16-bit integer.
    

    or alternatively:

    unsigned int x = 65529;
    int y = (int16_t) x;    //  This is defined in <stdint.h>
    
    0 讨论(0)
  • 2020-12-05 14:59

    Since converting unsigned values use to represent positive numbers converting it can be done by setting the most significant bit to 0. Therefore a program will not interpret that as a Two`s complement value. One caveat is that this will lose information for numbers that near max of the unsigned type.

    template <typename TUnsigned, typename TSinged>
    TSinged UnsignedToSigned(TUnsigned val)
    {
        return val & ~(1 << ((sizeof(TUnsigned) * 8) - 1));
    }
    
    0 讨论(0)
  • 2020-12-05 15:00

    I know it's an old question, but it's a good one, so how about this?

    unsigned short int x = 65529U;
    short int y = *(short int*)&x;
    
    printf("%d\n", y);
    
    0 讨论(0)
提交回复
热议问题