【问题标题】:Count 1's in a signed byte在有符号字节中计数 1
【发布时间】:2022-01-24 17:04:11
【问题描述】:

我这里有这个函数来计算一个字节中的1 位。但是,当我尝试将 char 值设置为 200 时,它会中断。但是,如果我将char 更改为unsigned char,它就可以工作。我很好奇为什么。

int bit_counter (char b){
    char count = 0;
    
    while (b != 0){
        if (b & 0x01){ 
            count ++;
        }
        b = b >> 1;
    }
     return count;
}

I have solved this issue. I masked all the bits, but the most significant bit.

int bit_counter (char b){
    char count = 0;
    
    while (b != 0){
        if (b & 0x01){ 
            count ++;
        }
        b = b >> 1;
        b = (b & 0x7F);
    }
     return count;
}

【问题讨论】:

  • 如果您使用的是 C++ 20,则有 std::popcount
  • char 的最大值是127(假设它是一个 8 位有符号值)
  • 如果 8 位 char 在您的平台上签名(而且很可能是),则不存在值 200 的 8 位签名字符。合法值为 -128....127。也就是说,并且保护您如何在char 中存储这样的值,您可能遇到的是对有符号值进行算术右移的符号扩展。 See this answer.
  • 尝试使用uint8_t 而不是charuint8_t 会告诉编译器你想要一个无符号的 8 位变量。
  • @Eljay 对于signed,它的实现定义了负值会发生什么,因此它可能变为正值(即使大多数实现“移入”@987654336 @ 保持消极)

标签: c++ binary char bit


【解决方案1】:

这个比较棘手,我们得看看char的组成。 首先,当您的函数中有 0 < b < 128 时,它运行良好。

您使用的是签名字符。一个有符号字符由一个符号位和 7 位数据组成。这意味着您只能拥有从 -128 到 127 的 7 位值。 char representation here.

当您分配b = 200 时,您会发生溢出,这意味着您超出了 127,它将采用另一个由 200 表示的值。我假设编译器采用 200 的二进制表示,即:

1100 1000 : 加粗的1是符号位的值(这里表示为负数)。

当你对 b 的内容进行位移时,你只位移了数据位。所以接下来的迭代看起来像:

1110 0100

1111 0010

1111 1001

...

1111 1111

对应于值 -1(请参阅two's complement。char 的零表示为 0000 0000。 所以 b 永远不会是 0,你会陷入无限循环......

如果你想解决这个问题,你可以使用unsigned char(不带符号位,用数据代替),或者你可以迭代 b 类型的大小:

int bit_counter (char b){
  char count = 0;
  // sizeof(type) = byte size and -1 because there is the sign bit
  for(int bitIndex = 0; bitIndex < (sizeof(char) * 8) - 1; ++bitIndex){
      if (b & 0x01){ 
          count ++;
      }
      b = b >> 1;
  }
  return count;
}

【讨论】:

  • “符号位和 n 位数据”:这将是符号和大小表示。不太可能适用于 OP。
  • 我把代码简单地粘贴到编译器资源管理器中,使用 gcc 11.2、clang 11.0 和 msvc 时,您会有这种行为:godbolt.org/z/nP3fYxfqo 虽然位移确实不能取代0,因为它使用二进制补码,我将更正这部分。
【解决方案2】:

在现代 c++ 中最好使用标准库 std::bitset。就像许多人在 cmets 中所说的那样,您可能已经了解使用内置类型的缺点。

std::bitset&lt;N&gt; 有一个函数 count,它会返回设置为 true (1) 的位。

几个例子

    std::bitset<8> testBitSet { "11110000" }; //std::bitset<N> -- N (num of bits)
    std::cout << testBitSet.count() << std::endl; //4

    std::bitset<8> testBitSet2{ "11111111" };
    std::cout << testBitSet2.count() << std::endl; //8

    //The first 8 are considered
    std::bitset<8> testBitSet4{ "00000011111111" }; //2
    std::cout << testBitSet4.count() << std::endl;

//Construcing with a number
std::bitset<8> testBitSetWithNum(200);
std::cout << testBitSetWithNum.count() << std::endl; //3
std::cout << testBitSetWithNum << std::endl; //11001000

【讨论】:

    猜你喜欢
    • 2012-04-15
    • 2014-12-06
    • 2021-09-20
    • 2017-10-01
    • 2014-11-26
    • 2015-01-17
    • 2011-10-21
    • 2018-04-07
    • 1970-01-01
    相关资源
    最近更新 更多