In computer science, the most simple information unit we have is called the “bit”, or “binary digit”. This is because they can only have 0 or 1 as possible values. Every piece of digital data we work with is constructed from bits, with groups of bits forming types of bytes, with different prefixes. Since data is stored at the bit level, being able to effectively use bitwise operators is essential to carry out low-level programming. In this article, we’re going to explain what bitwise operators in C are, the different types, and how and when to use each.

## What Are Bitwise Operators in C?

Bitwise operators in C are operators that work at the bit level. This is known as bit-level or low-level programming. Instead of manipulating larger data structures, here we’re interested in manipulating the blocks that represent the data. There are many types of bitwise operators in C, but these are the main ones:

- Bitwise AND (&) – This takes two numbers as operands (the value the operator acts on). If the bits are set to 1, then the result is 1. Otherwise, the result is 0.
- Bitwise OR (|) – This operator takes to numbers and sets each bit to 1 if either or both of them are 1 already.
- Bitwise complement (~) – This operator flips the value of each bit, from 1 to 0 or from 0 to 1, to invert the individual bits.
- Bitwise XOR (^) – Also known as the exclusive OR operator, XOR also sets the bits to 1 if either of them is already 1. However, XOR is considered true, i.e. sets the bit to 1, if exactly 1 of the operands is true, rather than 1 or both.
- Bitwise left shift (<<) and Bitwise right shift (>>) – These operators take two operands, the value to be shifted and the number of positions it’s to be shifted by. Bits shifted to the left are removed and zeroes are shifted in from the right in the case of the left shift operator. The opposite is true for the right shift operator. In essence, this results in each value being multiplied by 2 for each left shift, or each right shift, depending on the operator being used.

Now we’ve covered these briefly, it’s time to look a bit closer at how each of these operators works.

### AND operator

This operator is denoted by the & sign. An example of the bitwise AND operator being used follows.

```
#include <stdio.h>
int main() {
unsigned int value1 = 0b11011010;
unsigned int value2 = 0b10101010;
unsigned int result = value1 & value2;
printf("Result: %u\n", result);
return 0;
}
```

Like with most code, we include the header file and define the main “int” method. We then declare two unsigned variables (variables with non-negative values), “unsigned int value1” and “unsigned int value2”. These are initialized with the binary values “0b11011010” and “0b10101010” respectively, which are equivalent to the values “218” and “170”.

After this, we perform the bitwise AND operation, storing the result in the “result1” variable. The result is then printed, as can be seen in the image. The resulting value is equal to 138.

Lastly, we’re quickly going to look at the truth table for this operator. A truth table is a representation showing all the possible outputs of an operation. We can use this to evaluate its behavior. For the AND operator, the truth table is as follows:

Operand 1 | Operand 2 | Result |
---|---|---|

FALSE | FALSE | FALSE |

FALSE | TRUE | FALSE |

TRUE | FALSE | FALSE |

TRUE | TRUE | TRUE |

### OR operator

Represented by the | sign, the bitwise OR operator is also used to combine bits, but in a different way. Whereas the AND operator sets the result to 1 if both bits are 1, OR sets it to 1 if either or both are 1 already. For an example, consider this code:

```
#include <stdio.h>
int main() {
unsigned int value1 = 0b11011010;
unsigned int value2 = 0b10101010;
unsigned int result = value1 | value2;
printf("Result: %u\n", result);
return 0;
}
```

We have the same unsigned variables as before. We perform the OR operation, where the bit values are combined. This gives a different result, equivalent to 250, as seen in the output.

Here is the truth table for the OR operator.

Operand 1 | Operand 2 | Result |
---|---|---|

FALSE | FALSE | FALSE |

FALSE | TRUE | TRUE |

TRUE | FALSE | TRUE |

TRUE | TRUE | TRUE |

### XOR operator

Represented by ^, the bitwise XOR operator sets the output to 1 if any of the bits are already 1. Continuing with the same example, the code is given next.

```
#include <stdio.h>
int main() {
unsigned int value1 = 0b11011010;
unsigned int value2 = 0b10101010;
unsigned int result = value1 ^ value2;
printf("Result: %u\n", result);
return 0;
}
```

We can see that the unsigned variables are the same, but we get another result this time. The result is equivalent to 112, as we can see in the image.

Next is the truth table for the XOR operator.

Operand 1 | Operand 2 | Result |
---|---|---|

FALSE | FALSE | FALSE |

FALSE | TRUE | TRUE |

TRUE | FALSE | TRUE |

TRUE | TRUE | FALSE |

### Complement operator

Now it’s time for a slightly different operation. To see the complement bitwise operator in action, consider this code.

```
#include <stdio.h>
int main() {
unsigned int value = 10;
unsigned int complement = ~value;
printf("Complement: %u\n", complement);
return 0;
}
```

This time, we take a different unsigned variable, initialized with the value of 10, as well as another, called “complement”. We then use the complement operator, “~”, to invert the bits, and the result is printed.

The truth table for this operator is given next.

Operand | Result |
---|---|

FALSE | TRUE |

TRUE | FALSE |

### Left shift and right shift operators

The workings of the left and right shift bitwise operators aren’t as intuitive as the other operators. Let’s demonstrate both with an example.

```
#include <stdio.h>
int main() {
unsigned int value = 10;
unsigned int left_shifted_value = value << 2;
unsigned int right_shifted_value = value >> 2;
printf("Left Shifted Value: %u\n", left_shifted_value);
printf("Right Shifted Value: %u\n", right_shifted_value);
return 0;
}
```

We start with the unsigned value 10, and then declare 2 additional variables, “left_shifted_value” and “right_shifted_value”. We perform a left shift and a right shift operation, with the results assigned to these variables. The results are then printed, as we can see in the image. The original binary is 00001010 but ends up as 00101000 and 00000010 for the left shift and right shift operations respectively. This gives results of 40 and 2.

To finish, the truth tables are next. First is the left shift operator table.

Input | Shift amount | Result |
---|---|---|

0 | 0 | 0 |

0 | 1 | 0 |

1 | 0 | 1 |

1 | 1 | 2 |

Next is the truth table for the right shift operator.

Input | Shift amount | Result |
---|---|---|

0 | 0 | 0 |

0 | 1 | 0 |

1 | 0 | 1 |

1 | 1 | 0 |

## Pros, Cons, and Applications of Bitwise Operators in C

Now we understand the basic workings of the bitwise operators, exploring their advantages, drawbacks and useful applications would be a good idea. A summary of the pros and cons is given in the following table.

Pros | Cons |
---|---|

Allows efficient manipulation of bits | Make code less readable, particularly if the programmer is unfamiliar with binary digits |

Saves on memory, because they can be used to represent multiple values in one variable | Performance depends heavily on the platform used |

Quicker execution than typical operations | Only applicable in low-level programming |

Can lead to type safety issues as the data type isn’t considered |

The applications of each bitwise operator are described in the next table. These aren’t limited to the operator in question, but these are how they’re ideally used.

Operator | Application |
---|---|

AND | For masking specific bits, used for extraction |

OR | Setting bits, or bit masking |

XOR | Flip individual bits |

Complement | Flip all the bits in a binary number |

Left shift and right shift | Multiply or divide by powers of 2 |

## Bitwise Operators in C: Wrapping Up

To conclude, bitwise operators in C are essential tools in low-level programming, where we need to manipulate individual bits that represent our data. The main operators are AND, OR, XOR, Complement, Left shift, and Right shift. Most operators share similar functions but do have their own individual use cases. Used correctly, bitwise operators are effective at handling memory usage and performing fast operations. They’re applicable in bit manipulation, as well as fields like cryptography and network protocols. Once you understand how bitwise operators work, you’ll be able to work with your data more flexibly.