Cleanest way to combine two shorts to an int

后端 未结 7 1265
野的像风
野的像风 2020-12-17 23:31

I have two 16-bit shorts (s1 and s2), and I\'m trying to combine them into a single 32-bit integer (i1). According to the spec I\'m dealing with, s1 is the most significant

相关标签:
7条回答
  • 2020-12-17 23:46

    You want to cast data.first to an int32 before you do the shift, otherwise the shift will overflow the storage before it gets a chance to be automatically promoted when it is assigned to combined data.

    Try:

    const utils::int32 combineddata = (static_cast<utils::int32>(data.first) << 16) | data.second;
    

    This is of course assuming that data.first and data.second are types that are guaranteed to be precisely 16 bits long, otherwise you have bigger problems.

    I really don't understand your statement "if data.second gets too big, the | won't take account of the fact that they're both shorts."

    Edit: And Neil is absolutely right about signedness.

    0 讨论(0)
  • 2020-12-17 23:53

    Since nobody posted it, this is what the union would look like. But the comments about endian-ness definitely apply.

    Big-endian:

    typedef union {
        struct {
            uint16_t high;
            uint16_t low;
        } pieces;
        uint32_t all;
    } splitint_t;
    

    Little-endian:

    typedef union {
        struct {
            uint16_t low;
            uint16_t high;
        } pieces;
        uint32_t all;
    } splitint_t;
    
    0 讨论(0)
  • 2020-12-17 23:57

    Try projecting data.second explicite to short type, like:

    const utils::int32 combineddata = ((data.first<<16) | ((short)data.second));
    

    edit: I am C# dev, probably the casting in your code language looks different, but idea could be the same.

    0 讨论(0)
  • 2020-12-17 23:59

    What you've got looks nearly correct, but will probably fail if the second part is negative; the implicit conversion to int will probably sign-extend and fill the upper 16 bits with ones. A cast to unsigned short would probably prevent that from happening, but the best way to be sure is to mask off the bits.

    const utils::int32 combineddata = ((data.first<<16) | ((data.second) & 0xffff));
    
    0 讨论(0)
  • 2020-12-18 00:05

    What you are doing is only meaningful if the shorts and the int are all unsigned. If either of the shorts is signed and has a negative value, the idea of combining them into a single int is meaningless, unless you have been provided with a domain-specific specification to cover such an eventuality.

    0 讨论(0)
  • 2020-12-18 00:05

    Using a union to do the job looks like a good choice, but is a portability issue due to endian differences of processors. It's doable, but you need to be prepared to modify your union based on the target architecture. Bit shifting is portable, but please write a function/method to do it for you. Inline if you like.

    As to the signedness of the shorts, for this type of operation, it's the meaning that matters not the data type. In other words, if s1 and s2 are meant to be interpreted as two halves of a 32 bit word, having bit 15 set only matters if you do something that would cause s2 to be sign extended. See Mark Ransoms answer, which might be better as

    inline utils::int32 CombineWord16toLong32(utils::int16 s1, utils::int16 s2)
    {
        return ((s1 <<16) | (s2 & 0xffff));
    }
    
    0 讨论(0)
提交回复
热议问题