【问题标题】:Convert bitset<a> to signed int, with a<32>使用 a<32> 将 bitset<a> 转换为有符号整数
【发布时间】:2015-02-07 07:10:39
【问题描述】:

我正在阅读问题convert bitset to int in c++ 并想,嘿,这行不通,我已经尝试过了。但后来我开始尝试,很快我发现:

#include <bitset>
#include <iostream>
int main()
{
   std::bitset<31> b31(-1);
   std::bitset<32> b32(-1);
   std::cout<<static_cast<int>(b31.to_ulong())<<std::endl;
   std::cout<<static_cast<int>(b32.to_ulong())<<std::endl;
   return 0;
}

给出输出

2147483647
-1

那么,如何将小于 32 的位集转换为有符号整数?

澄清:我想用构造保留的位集时使用的 10 基值转换回带符号的 int。 “将签名的整数存储在位集中”

我在win 7上用gcc 4.6.2、mingw32试过这个,用c-style cast(int)得到同样的结果

【问题讨论】:

  • Fwiw,这会在带有 clang 3.5 的 OSX x64 上生成 -1 -1
  • 不错不错!我正要问我是否误解了to_ulong() 规范,或者它是否是特定于编译器的。如果读者愿意尝试,了解其他编译器如何处理这个问题会很有趣,例如 MSVC、intel ;)

标签: c++ std bitset std-bitset


【解决方案1】:

这样的事情怎么样:

#include <bitset>
#include <iostream>

template<std::size_t B>
long bitset_to_long(const std::bitset<B>& b) {
  struct {long x:B;} s;
  return s.x = b.to_ulong();
}

int main()
{
   std::bitset<31> b31(-1);
   std::bitset<32> b32(-1);
   std::cout << bitset_to_long(b31) << std::endl;
   std::cout << bitset_to_long(b32) << std::endl;
   return 0;
}

(灵感来自Sign extending from a constant bit-width。)

【讨论】:

    【解决方案2】:

    制作一个剩余高位为 1 的掩码,当位集中的最高有效位设置为 1 时,将其与强制转换中的无符号值进行或运算,如下所示:

    const int sz = 15;
    std::bitset<sz> b(-1);
    int num = static_cast<int>(b.to_ulong());
    if (b[sz-1]) {
        int mask = (1<<sz)-1;
        num |= ~mask;
    }
    std::cout << num << std::endl;
    

    表达式(1&lt;&lt;sz) 生成一个仅设置了sz 位的数字。 (1&lt;&lt;sz)-1 制作一个掩码,最后一个 sz-1 位设置为 1s。 ~ 反转它,产生一个二进制补码到你的位集的值。

    Demo.

    【讨论】:

    • 我认为关键是bitset的MSB应该被视为符号位。除非我看错了,否则你会把一切都变成负面的。
    • @hvd 我认为你是对的。不过,我希望 OP 提供更多示例。无论如何,现在已经解决了。
    • 为问题添加了详细信息
    【解决方案3】:

    你需要sign extension

    #define BITLEN 31
    #define SHIFT_AMOUNT (sizeof(int)*CHAR_BIT - BITLEN)
    
    std::bitset<BITLEN> b31(-1);
    int v = (static_cast<int>(b31.to_ulong()) << SHIFT_AMOUNT) >> SHIFT_AMOUNT;
    std::cout << v << std::endl;
    

    从技术上讲,有符号类型的右移是实现定义的,但所有现代实现都会进行算术移位,因此这不是真正的问题。但是,如果您真的想避免这种行为,请使用著名的 bit twiddling hacks 中的便携式替代方法

    template <typename T, unsigned B>
    inline T signextend(const T x)
    {
        struct {T x: B;} s;
        return s.x = x;
    }
    
    signextend<int, 31>(b31.to_ulong());
    

    【讨论】:

    • 负数右移具有实现定义的结果,因此这可能不适用于所有平台。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-17
    • 2019-05-30
    • 2018-11-12
    • 2020-06-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多