我想使用整数的高半部分存储一些值。现在,在上半部分中,我想再次存储以下两个不同的值。
如果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);
尽管这似乎可行,但在某些情况下可能会失败或有更好的解决方案。
答案 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可能不会。 here和here中提供了有关GCC如何允许这种未定义行为的更多详细信息。