Changing specific set of bits in a byte

自古美人都是妖i 提交于 2019-12-11 15:03:21

问题


I am working on a function that receives a byte and needs to change some of the bits in that byte.

For example, the function receives:

11001011

Then I need to set the MSB to 0, its easy enough:

buffer[0] &= ~(1 << 7);

But then I need to set bits 6 through 3 (I refer LSB as bit 0 here) to an argument that gets supplied to the function. This argument can be an integer from 0 to 6.

The important thing is I should not change any other bits.

I tried with masking and stuff but I failed miserably. Then as last resort I did it painfully like below. It works fine...but it is ugly and generates tons of instructions, making the code run slow:

    switch(regAddress) {
        case 0:
            buffer[0] &= ~(1 << 5);
            buffer[0] &= ~(1 << 4);
            buffer[0] &= ~(1 << 3);
        break;

        case 1:
            buffer[0] &= ~(1 << 5);
            buffer[0] &= ~(1 << 4);
            buffer[0] |=  (1 << 3);
        break;

       //YOU GOT THE IDEA!!.....
     }

Please let me know hot to do this in one (or two) line of code so I can learn the trick.

I did a mistake, the argument passed is alway 0 to 6, so the MSB of the 4bits that I want to set is always zero, therefore before the switch case I did like:

//because we only have 7 address, we already set the 4th bit to 0
buffer[0] &= ~(1 << 6);

回答1:


If you have a bit field, say bits 6 though 3 (four bits total), packed into a value w (some type of unsigned integer), then you can set the field with a value v with:

w = (w & ~0x78) | (v << 3);

This assumes that v is within the required range. If not, you can use (v & 0xf) in place of v. The mask operation w & ~0x78 clears bits 6 through 3, the shift operation moves v into the proper position, and the bitwise-or operation combines them.

To extract the field from w, you can use:

(w >> 3) & 0xf

The shift operation right-justifies the field, and the mask operation clears the bits outside of the field. This is equivalent to:

(w & 0x78) >> 3

This version masks the field before shifting (so it uses a larger mask value).

Make sure w has an unsigned type so that the shifts are unsigned.

Note: This example is for the 4-bit field occupying bits 6, 5, 4, 3. The 0x78 mask is ((1 << 4) - 1) << 3, i.e. 0xf << 3. The 0xf mask is (1 << 4) - 1. And the shift amount, 3, is the number of bits to the right of the field, i.e. bits 2, 1, and 0.




回答2:


Why not loop over the set of bits?

def setBits(i, bits):
    for bit in bits:
        i |= 1 << bit
    return i

print(bin(setBits(0b11001011, [3, 4, 5, 6])))


来源:https://stackoverflow.com/questions/47128112/changing-specific-set-of-bits-in-a-byte

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!