将整数设置为高位,而不考虑其中的位数

时间:2018-09-07 05:19:02

标签: c++ c bit-manipulation

我想使用整数的高半部分存储一些值。现在,在上半部分中,我想再次存储以下两个不同的值。

如果long是32位,我想使用前8位和后8位(从左开始)。

如果long是64位,我想使用前16位和后16位(从左开始)。 我想出了类似下面的内容。

unsigned long foo;
unsigned long bar = 1UL; // i'll ensure this value fits in 2 bits to handle 16 bits integer.
unsigned long baz = 1UL; // i'll ensure this value fits in 2 bits.
int BitsInLong = CHAR_BIT * sizeof(unsigned long);
foo |= bar << (BitsInLong / 2 + BitsInLong / 4);
foo |= baz << (BitsInLong / 2);

尽管这似乎可行,但在某些情况下可能会失败或有更好的解决方案。

2 个答案:

答案 0 :(得分:0)

只有一个问题-字段溢出。如果(附近)中间字段设置了较大的值,则该值可能会溢出到下一个字段。

这是一种通用解决方案,它可以与位数被4整除的类型(标准系统上的所有常规类型为true)一起使用:

template <typename T, unsigned Field>
constexpr T make_field(unsigned value)
{
  static_assert(std::numeric_limits<T>::is_integer, 
                  "works only with integers");
  static_assert(Field <4, "a field can be 0,1,2,3 ");
  using UT = typename std::make_unsigned<T>::type;
  constexpr unsigned bits = std::numeric_limits<UT>::digits;
  static_assert(bits % 4 == 0, "number of bits in return type must be divisible by 4");
  auto mask = ((UT)1 << (bits / 4)) - 1;
  return (value & mask) << ((3 - Field) * bits / 4);
}

以及用法

int main()
{   
     // will print 700, since upper bits are truncated.
    std::cout << std::hex << (make_field<int12_t, 1>(0x127) << '\n';

    // will print 7000
    std::cout  << (make_field<int12_t, 0>(0x127) << '\n';

    // prints 1234
    std::cout << (make_field<int, 0>(0x12) | make_field<int, 1>(0x34)) << "\n";
}                           

注意:带符号的整数类型如果不是二进制补码格式,并且设置了高位,则可能会以不可预测的方式工作。

答案 1 :(得分:-1)

模板化联合怎么样?

template <typename T>
union segmentedStorage {
  std::array<unsigned char, sizeof(T)> byteRepr;
  T     fullRepr;
  static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value);
  static_assert(sizeof(T) % 4 == 0);
};

Godbolt示例:https://godbolt.org/z/R0vtfT

对于:: value类型,这需要C ++ 17。当心严格的别名规则。我想您将要编写字节表示形式,然后读取完整的表示形式,但这在技术上是未定义的行为。 GCC保证I think的行为符合预期。 lang可能不会。 herehere中提供了有关GCC如何允许这种未定义行为的更多详细信息。