Store a char value on an int using bitwise and keep value sign value correct when getting it back without a cast

0

I have some signed 8 bit values that I want to store on a signed 32 bit integer.

I do that moving the values using bitwise shift left:

const auto value1 = char{90};
const auto value2 = char{80};
const auto value3 = char{70};
const auto value4 = char{60};

auto merged_value = int32_t{0};
merged_value |= (value1 & 0x000000FF) << 24;
merged_value |= (value1 & 0x000000FF) << 16;
merged_value |= (value1 & 0x000000FF) << 8;
merged_value |= value1 & 0x000000FF;

Now, let's say I want to get back value1 from merged_value I will do that like this:

const auto back_value1 = (merged_value >> 24) & 0x000000FF;

This works great as long as value1 is a positive number, but if the value is negative, the return value will be wrong.

For example, if value1 is -80, then back_value1 will be 176, that's because the most significant bit (the positive or negative bit) is in bit position 7 and not in 31 (since back_value1 is an int32_t).

Now, I know that I just need to do a cast to char on back_value1 and I will get the -80 value back. But what I want is a bitwise operation(s) that will give me the correct value -80 to back_value1 when back_value1 is an int32_t and without a cast to char.

Thanks

Edit:

Neil Butterworth asked that I post the entire code here instead of on an online IDE, so here it is:

#include <iostream>
#include <bitset>

int main()
{
  const auto value = char{-80};
  std::cout << "value: " << (int)value << std::endl;

  std::cout << "value bits: " << std::bitset<32>(value) << std::endl;

  auto merged_value = uint32_t{0};
  merged_value |= (value & 0x000000FF) << 24;

  const auto back_value = int32_t(merged_value >> 24) & 0xFF;

  std::cout << "value: " << back_value << std::endl;
  std::cout << "back_value bits: " << std::bitset<32>(back_value) << std::endl;
}
c++
bit-manipulation
bit-shift
asked on Stack Overflow Sep 1, 2017 by E. B. • edited Sep 1, 2017 by E. B.

1 Answer

0

The answer is that to get the value back as an int32_t with the same sign as the original int8_t, you need to either:

cast back to a int8_t:

const auto back_value1 = int32_t(int8_t((merged_value >> 24) & 0xFF));

or make sure the byte you need is at the left end of the int32_t before right shifting:

const auto back_value1 = merged_value /* << 0 */ >> 24;
const auto back_value2 = merged_value << 8 >> 24;

Needless to say, I don't recommend the latter.

answered on Stack Overflow Sep 1, 2017 by md5i

User contributions licensed under CC BY-SA 3.0