0

I know there is another post here that is how to clear a single bit, but how about a whole byte?

For example, if I had 00000000 00000000 00101100 11000100 and I wanted to clear the second chunk so it was now 00000000 00000000 00000000 11000100, how would I go about doing that? I know I need to use bitwise &.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 3
    `number & 0xFF` – isrnick May 22 '20 at 05:18
  • Awesome thank you! – PhantomProgramer May 22 '20 at 05:22
  • 6
    `number & 0xFFFF00FF`? This preserves the bits in the 3 bytes that you didn't say you wanted edited. If the leading 16 bits are zeros, there's no net difference between this and `number & 0xFF`, but if you had `01010110 11110000 00101100 11000100`, using just `0xFF` would clear the most significant 3 bytes. – Jonathan Leffler May 22 '20 at 05:22
  • 1
    It sometimes is easier to think of it in terms of the complimentary value. So, let's say you have `const uint32_t mask = 0x0000ff00;` representing those bits. To clear them is `number & ~mask` / to isolate them is `number & mask` / to turn them all on is `number | mask`. – paddy May 22 '20 at 05:27
  • Some candidates: *[How to replace bits in a bitfield without affecting other bits using C](https://stackoverflow.com/q/5925755)* (2011), and *[How do you set only certain bits of a byte in C without affecting the rest?](https://stackoverflow.com/q/4439078)* (2010) – Peter Mortensen Sep 13 '22 at 09:59

2 Answers2

3

To clear specific bits within a memory area you can use the bitwise And operator, &, along with a mask. To create the mask, rather than thinking of which bits you want to clear, you should instead think of which bits you want to keep and create the mask using those bits.

The mask should be the same type of variable as the type of variable stored in the memory area. So if you are wanting to clear bits in a long variable then you would create a mask in another long variable which indicates the bits you want to keep.

Assume you have a variable of type unsigned long which contains the bit pattern 00000000 00000000 00101100 11000100 and you want to clear the bits in the second byte from the right, the eight bits of 00101100 while keeping the other bits.

First you create a mask that has the bits you want to keep as in 11111111 11111111 00000000 11111111 or 0xffff00ff. If you want to clear all other bits except for the least significant byte then you could use 0xff for your mask.

Next you use the bitwise And operator & to and the variable with the mask. Many times you would use the &= operator with the variable containing the value with bits to clear on one side of the operator and the mask indicating which bits to keep on the other.

unsigned long x1 = 0x2cc4;  // variable to mask.
unsigned long mask = 0xffff00ff;  // mask to zero all bits in the second byte from the right

x1 &= mask;  // keep only the bits we want to keep

Or you could hard code the mask as in:

unsigned long x1 = 0x2cc4;

x1 &= 0xffff00ff;  // keep only the bits we want to keep

Or if you don't want to modify the original variable something like:

unsigned long x1 = 0x2cc4;  // variable to mask.
unsigned long x2 = 0;       // variable for new, masked value of x1
unsigned long mask = 0xffff00ff;  // mask to zero all bits in the second byte from the right

x2 = x1 & mask;  // keep only the bits we want to keep and put into a new variable

The bitwise And operator does an And operation on each bit and the resulting output bit for each bit is calculated using an And truth table. 0 And either 0 or 1 results in a 0 and only if both bits are 1 will a 1 result.

      0  |   1
   -----------
 0 |  0  |   0
 1 |  0  |   1

As a side note you can also set the bits you want to clear in the mask and then use the bitwise Not operator, ~, and turn the mask from a mask of bits you want to clear to a mask of bits you want to keep. However this is not the way that it is usually done so may be confusing to other programmers reading the code.

unsigned long x1 = 0x2cc4;
unsigned long mask = ~0xff00;  // mask to zero all bits in the second byte from the right

x1 &= mask;  //  And to keep only the bits we want to keep

Note also that the C Standard is a bit loose about how many bits are actually included in the most commonly used variable types such as int, short, long, etc. There are guarantees about the minimum size but not necessarily the maximum size. This was done in order to provide backward compatibility as well as to allow portability of source code and flexibility for compilers targeting specific hardware platforms. However it means that if you depend on the implementation of int as 64 bit in source code that is then moved to 32 bit hardware you may be surprised by the behavior.

The header file stdint.h specifies a number of exact width integer types such as int8_t and others. See stdint.h — Integer types however not all compiler vendors will provide support though most up to date compilers do.

As an aside, using hard coded numeric values such as 0xff for a bit mask that is intended to be used in several places and has a specific meaning (e.g. buffer size field) is generally frowned upon. The normal practice is to use a #define macro with a descriptive label, usually within an include file if the constant is needed in multiple source files, to name the bit mask in C programs. Creating a defined constant allows there to be a single point of definition for the bit mask constant thereby providing consistency of use, it will be right everywhere or wrong everywhere. Doing this also provides a unique, searchable identifier for the bit mask constant should you need to find where it is being used. In C++ a const variable such as const unsigned long BitMaskA = 0x00ff; is normally used instead of a #define as such a variable defaults to internal linkage in C++, though it defaults to external linkage in C, and not depending on the Preprocessor is encouraged for C++ (see https://stackoverflow.com/a/12043198/1466970)

Note as well that using bitfield variable types is a different mechanism than using the bitwise operators with masks. For instance see When to use bit-fields in C? as well as this answer which talks to the portability problem https://stackoverflow.com/a/54054552/1466970

Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
1

Suppose you want to clear the bits from s(start) to e(end) in the bit vector BV. And total number of bits in a number is b. Proceed as follows:

mask = ~0;

This will set all the bits. Something like 11111111

mask = mask >> (b - (e - s + 1));

This will give something like 00000111, with number of set bits equal to number of bits you want to clear.

mask = mask << s;

This will move the set bits to the desired positions. Something like 00111000

mask = ~mask;

This will give 11000111

Now perform & with the bit vector

B &= mask;

This will clear the bits from s to e.