1

I have this function here to count 1 bits in a byte. However, when I try putting the char value of 200, it breaks. However, if I changed the char to unsigned char, it works. I am curious as to why.

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;
}

  • 2
    If you are using C++ 20, there is [std::popcount](https://en.cppreference.com/w/cpp/numeric/popcount). – PaulMcKenzie Jan 24 '22 at 17:19
  • 1
    the maximum value of `char` is `127` (assuming its an 8-bit signed value) – Alan Birtles Jan 24 '22 at 17:23
  • If 8-bit `char` is signed on your platform (and it, in all likelihood, is), there is no such thing as an 8-bit signed char with a value of 200. The legal values are in -128....127. That said, and belaying how you're storing such a value in `char`, what you're probably experiencing is sign-extension of arithmetic right shift on a signed value. [See this answer](https://stackoverflow.com/a/61895313/1322972). – WhozCraig Jan 24 '22 at 17:24
  • Try using `uint8_t` instead of `char`. The `uint8_t` will tell the compiler you want an unsigned 8-bit variable. – Thomas Matthews Jan 24 '22 at 17:32
  • For a signed char that is negative, the `b = b >> 1;` will never become 0. – Eljay Jan 24 '22 at 17:44
  • 1
    @Eljay For a `signed` it's implementation-defined what happens to a negative value, so it _could_ become positive (even though most implementations "shift in" a `1` to keep it negative) – Ted Lyngmo Jan 24 '22 at 17:47
  • Note that this will all be very visible when you run your program under a debugger and watch how the value of `b` changes. – Useless Jan 24 '22 at 17:48
  • Is there any reason to not just cast that char to an unsigned char first? – harold Jan 24 '22 at 18:00
  • I know that if I change it to unsigned char it will work. I am testing how it can work with a char value. – Alon Gottlieb Jan 24 '22 at 18:09

2 Answers2

0

This one is pretty tricky, and we have to look at the composition of a char. First it works well, when you have 0 < b < 128 in your function.

What you use is a signed char. A signed char is composed of a sign bit and 7 bits of data. Meaning you can only have with 7 bits values from -128 to 127. char representation here.

When you assign b = 200 you have an overflow, meaning you go beyond 127 and it will take another value represented by 200. I assume the compiler takes the binary representation of 200 which is:

1100 1000 : The 1 in bold is the value of the sign bit (here indicating it is negative).

When you bit shift the content of b, you shift only the data bits. So the next iterations would look like:

1110 0100

1111 0010

1111 1001

...

1111 1111

Which corresponds to the value -1 (see two's complement. A zero representation for char is 0000 0000. So b will never be 0, and you are stuck in an infinite loop...

If you want to fix the issue you can use unsigned char (without the sign bit, replaced by data), or you could iterate over the size of the b type:

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;
}
rodousse
  • 1
  • 3
  • "Sign bit and n bits of data": That would be sign-and-magnitude representation. Unlikely to apply to the OP. – Deduplicator Jan 24 '22 at 18:13
  • I took the code and simply pasted it in compiler explorer, you have this exact behavior using gcc 11.2, clang 11.0, and msvc: https://godbolt.org/z/nP3fYxfqo Although it is true that the bit shifting doesn't replace with 0, since it uses two's complement, I'll correct this part. – rodousse Jan 24 '22 at 18:24
0

In the modern c++ better to go with standard library std::bitset. Like many people said in comments, you might have understood the disadvantage of using inbuilt types.

The std::bitset<N> has a function count which returns you the bits that are set to true (1).

Few examples

    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
Pavan Chandaka
  • 11,671
  • 5
  • 26
  • 34