Search code examples
c++castingnarrowingtype-narrowing

Narrowly cast low-order bytes in C++


I tried to cast an int to a uint16_t with the following code:

std::cout << static_cast<std::uint16_t>(65537) << std::endl;

The output was 1. As far as I've got it, only the high-order bits got cast to the destination type. I'm not sure if this is implementation-defined (I used clang).

I wonder, is there an option to specify which bytes I want to get to the destination type when performing a narrowing conversion? Are there some casts to consider low-order bytes first?


Solution

  • Conversion to an unsigned type is done by reduction modulo 2N, where N is the number of bits in the destination type. This equates to keeping the N least significant bits of a 2's complement representation of the number in question.

    If you want to keep some more significant bits instead, you'll want to do a right shift on the value before converting to the destination type.

    uint32_t input = 0x12345678;
    
    uint16_t lower = static_cast<uint16_t>(input); // lower = 0x5678;
    uint16_t upper = static_cast<uint16_t>(input >> 16); // upper = 0x1234
    

    Be aware, however, that if you might have a negative value, you probably want to convert to an unsigned type of the same size first, then do the right shift on that result. Results of right shifting a negative number can vary.