masking most significant bit

2019-09-17 15:20发布

问题:

I wrote this function to remove the most significant bit in every byte. But this function doesn't seem to be working the way I wanted it to be.

The output file size is always '0', I don't understand why nothing's been written to the output file. Is there a better and simple way to remove the most significant bit in every byte??

回答1:

In relation to shift operators, section 6.5.7 of the C standard says:

If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.

So firstly, remove nBuffer << 8;. Even if it were well defined, it wouldn't be an assignment operator.

As people have mentioned, you'd be better off using CHAR_BIT than 8. I'm pretty sure, instead of 0x7f you mean UCHAR_MAX >> 1 and instead of 7 you meant CHAR_BIT - 1.

Let's just focus on nBuffer and bit_count, here. I shall comment out anything that doesn't use either of these.

 bit_count += 7;

 if (bit_count == 7*8)
  {
    *out_buf++ = nBuffer;
    /*if((write(out_fd, bit_buf, sizeof(char))) == -1)
      oops("Cannot write on the file", "");*/
    nBuffer << 8;
    bit_count -= 8;
  }
nBuffer = 0;
bit_count = 0;

At the end of this code, what is the value of nBuffer? What about bit_count? What impact would that have on your second loop? while (bit_count > 0)

Now let's focus on the commented out code:

    if((write(out_fd, bit_buf, sizeof(char))) == -1)
      oops("Cannot write on the file", "");

Where are you assigning a value to bit_buf? Using an uninitialised variable is undefined behaviour.



回答2:

Instead of going through all of the bits to find the high one, this goes through only the 1 bits. high() returns the high bit of the argument, or zero if the argument is zero.

inline int high(int n)
{
    int k;

    do {
        k = n ^ (n - 1);
        n &= ~k;
    } while (n);
    return (k + 1) >> 1;
}

inline int drop_high(int n)
{
    return n ^ high(n);
}


回答3:

unsigned char remove_most_significant_bit(unsigned char b)
{
    int bit;
    for(bit = 0; bit < 8; bit++)
    {
        unsigned char mask = (0x80 >> bit);
        if( mask & b) return b & ~mask;
    }
    return b;
}

void remove_most_significant_bit_from_buffer(unsigned char* b, int length)
{
    int i;
    for(i=0; i<length;i++)
    {
        b[i] = remove_most_significant_bit(b[i]);
    }
}



void test_it()
{
    unsigned char data[8];
    int i;
    for(i = 0; i < 8; i++)
    {
        data[i] = (1 << i) + i;
    }
    for(i = 0; i < 8; i++)
    {
        printf("%d\r\n", data[i]);
    }
    remove_most_significant_bit_from_buffer(data, 8);
    for(i = 0; i < 8; i++)
    {
        printf("%d\r\n", data[i]);
    }



}


回答4:

I won't go through your entire answer to provide your reworked code, but removing the most significant bit is easy. This comes from the fact that the most significant bit can easily be found by using log base 2 converted to an integer.

#include <stdio.h>
#include <math.h>

int RemoveMSB(int a)
{
    return a ^ (1 << (int)log2(a));
}

int main(int argc, char const *argv[])
{
    int a = 4387;

    printf("MSB of %d is %d\n", a, (int)log2(a));

    a = RemoveMSB(a);

    printf("MSB of %d is %d\n", a, (int)log2(a));
    return 0;
}

Output:

MSB of 4387 is 12
MSB of 291 is 8

As such, 4387 in binary is 1000100100011 with a most significant bit at 12.

Likewise, 291 in binary is 0000100100011 with a most significant bit at 8.