设置最高有效位

Set the most significant bit

我正在尝试根据 bool 标志切换 unsigned int 的最高有效位。这是我的假设代码 K = unit64_t:

这是Item class:

template<typename K>
class Item {
  public:
    K first;

    Item() = default;
    explicit Item(const K &elem, const bool flag = false) {
      first = elem & 0x3FFFFFFFFFFFFFFF;
      first |= (flag * 0x8000000000000000);
    }
};

有没有办法做到这一点完全通用?它适用于所有类型的数字 K?

我试过 8 * sizeof(K) 但它不起作用。

您可以为此利用 std::bitset。不确定这优化得有多好,但它应该优化得很好并且它可以正常工作并且不需要按位运算知识。

template <typename T>
void toggle_msb(T& val)
{
    constexpr auto bit_width = sizeof(T) * CHAR_BIT;
    std::bitset<bit_width> temp(val);
    val = temp.flip(bit_width - 1).to_ullong();
}

仅使用位操作的选项:

template<typename T>
void Item(T& elem, bool flag = false) {
    T mask = (T)1 << (sizeof(T) * 8 - 1);
    elem = (elem & ~mask) | (flag ? mask : 0);
}

使用按位运算,但不显式依赖T的大小:

template<typename T>
T set_top_bit(T value, bool state) {
    constexpr T mask = T(~T(0)) >> 1;
    value &= mask;
    if (state) value |= ~mask;
    return value;
}

T(~T(0)) 得到一个 T,所有位设置 1>> 1 抛出底部位从顶部得到 0,因此在 mask 中我们有一个 T 设置了所有位,但最高位除外。请注意,所有这些舞蹈都是纯粹正式的——this is all evaluated at compile time.

其余部分与您的代码非常相似:屏蔽掉 value 的最高位,然后根据 state 或将其返回(~mask 将是 T 只设置了最高位)。


  1. Plain ~0 会导致 int 设置为 -1,~0Uunsigned int 中设置所有位;要获得所有位都已设置的 T,我们需要翻转 T(0) 的位(因此,我们的 T 类型为 0),稍后还要转换回 T,因为,如果 T 小于 int~T(0) 实际上等于 ~int(T(0)),所以 ~0,由于整数提升规则。

从这个很棒的post,How do you set, clear, and toggle a single bit?,你可以使用这个无分支版本:

#include <climits>

template<typename T>
constexpr T set_top_bit_v2(T value, bool state) {
    constexpr auto msb = (sizeof(T) * CHAR_BIT) - 1;
    return (value & ~(T{1} << msb)) | (T{state} << msb);
}

将输出与 on Godbolt (here 进行比较),尽管存在差异 Clang 似乎生成相同的代码,而 GCC 和 MSVC 在使用此版本时似乎发出的指令较少。