Also, we will explain how to perform bit masking with logical operations, as this is something very useful in programming and is completely related to this type of operators.
Description of Bitwise Operations
The operations bitwise are logical and shift operations are applied individually to each bit of a variable. For example, if we apply the operation AND between the variables “a” and “b”, bit 0 of “a” will be linked to bit 0 of “b”, bit 1 of “a” will be linked to bit 1 of “b” “, and so on.
Each bit operates and returns its own result and has no influence on the result of the bits adjacent to it.
This type of operation is very useful in masking bits when using control flags or indicators grouped into a single data item such as an integer.
How to Assign a Binary Value to a Variable in the C Language
Before we begin to explain what bitwise logical operations are all about, let us look at how to assign a value to a variable in binary code because although we can do this in decimal, hexadecimal, or some other representation, visualizing 1s and 0s makes programming much more practical and understandable. For example, in cases where the bits represent control flags or indicators grouped into an int, double, or other variable.
To assign a value to a variable in binary format, we need to prefix the binary representation with “0b”. The following snippet assigns the value 131 or 0b10000011 to the integer “a” in binary format and then displays its decimal representation in the command console.
void main(){
int a;
a = 0b10000011;
printf("The decimal representation for 0b10000011 is: %i\n", a);
}
The image below shows the result for this code.
Representing binary values in bitwise and masking operations makes programming much more fluid and understandable and avoids errors or conversions that cost time.
NOT Operator
The logical operator for the NOT is the symbol “~”.
The logical NOT or negation operation is the simplest of all, having only one input and one output.
This operation returns in its output the inverted binary value of its input.
Consider the following expression for the logical operation NOT with the input “a”
The result in “c” is equal to 1 if “a” is equal to 0 and “c” is equal to 0 if “a” is equal to 1. This operation is commonly used to obtain the complementary value of a variable.
Next, let us look at the truth table for the NOT operation.
a | ~ | = | c |
0 | ~ | = | 1 |
1 | ~ | = | 0 |
Example:
In this example, we will apply the operation NOT to the variable a to get its complement in “c”
To do this, we create the variable a of type unsigned char, assign it the value 131, and get the result in “c”. We then use the printf() function to display the result in the command console. Below, we can see the code for this purpose.
void main()
{
unsigned char c;
unsigned char a;
a = 0b01111100;
c =~a;
printf(“\nThe decimal representation for 0b10000011 is: %i\n”, c);
}
In the figure below, we see the result of the complement of “a” . In this case, the complement or inverse of 131 is 124 or 01111100 in binary representation.
Logical AND Operator
The logical operator for the AND operation is the symbol “&”
Let us look at the following expression for the logical AND operation between the variables a and b
The result in “c” is equal to 1 only if “a” & “b” are equal to 1. In all other cases, “c” is equal to 0.
Next, we look at the truth table for the operation AND.
A | & | b | = | c |
0 | & | 0 | = | 0 |
0 | & | 1 | = | 0 |
1 | & | 0 | = | 0 |
1 | & | 1 | = | 1 |
The logical operation AND is very useful in bit masking. Later, we will see a section explaining this technique in more detail.
Example:
Now, let us see an example where we perform the logical AND operation between the variables “a” and “b” of type unsigned char and store the result in “c” to display it later in the command console.
We assign the value 135 or 10000111 to the variable “a” and 129 or 1000001 to the variable “b” in binary representation. Then, we will use the operator “&” ‘to perform the operation. Next, we will see the code for this.
void main()
{
unsigned char a = 0b10000111;
unsigned char b = 0b10000001;
unsigned char c;
c = a & b;
printf("\nThe result of a & b is: %i\n", c);
}
The image shows the result of this code where the AND operation between “a” and “b” results in 129 or 10000001 in binary.
Logical OR Operator
The logical operator for the OR operation is the symbol ” | “.
Let us look at the following expression for the logical OR operation between the variables a and b
The result in “c” will equal 1 only if “a” or “b” or “a” and “b” equal 1, while it will equal 0 only if “a” and “b” both equal 0.
Next, let us look at the truth table for the OR operation.
to | | | b | = | c |
0 | | | 0 | = | 0 |
0 | | | 1 | = | 1 |
1 | | | 0 | = | 1 |
1 | | | 1 | = | 1 |
Example
In this example we will see how to perform the logical operation OR between the variables ” a” and “b” of type unsigned char and store the result in “c” to display it later in the command console.
We assign the value 128 or 10000000 to the variable “a” and 3 or 00000011 to the variable “b” in binary representation. Then, we will use the operator “|”to perform the operation. Next, we will see the code for this operation.
void main()
{
unsigned char a = 0b10000000;
unsigned char b = 0b00000011;
unsigned char c;
c = to | b;
printf("\nThe result of a | b is: %i\n", C);
}
In the image below, we see the result of the operation c = a | b which in this case is 131 or 10000011 in binary.
Logical Operator XOR or Exclusive OR
The logical operator for the XOR operation is the symbol ” ^ “.
Let us look at the following expression for the logical XOR operation between the variables a and b
The result in “c” is equal to 1 only if one of the bits “a” or “b” is equal to 1, but it is 0 if “a” and “b” are both equal to 1 or equal to 0.
This operation is essential in adders because in binary system 1 + 0 = 1 or 0 + 1 is also equal to 1. But 1 + 1 = 0 with carry to the next higher bit. In this case, the carry is performed by the operation AND.
Next, we look at the truth table for the XOR operation.
a | ^ | b | = | c |
0 | ^ | 0 | = | 0 |
0 | ^ | 1 | = | 1 |
1 | ^ | 0 | = | 1 |
1 | ^ | 1 | = | 0 |
Example
Now, let us look at an example where we perform the logical XOR operation between the variables ” a” and “b” of type unsigned char and store the result in “c” to display it later in the command console.
We assign the value 135 or 10000111 to the variable “a” and 3 or 00000011 to the variable “b” in binary notation. Then, we will use the ” ^ ” operator to perform the logical operation. Next, we will see the code for this.
void main()
{
unsigned char a = 0b10000111;
unsigned char b = 0b00000011;
unsigned char c;
c=a ^ b;
printf("\nThe result of a | b is: %i\n", c);
}
As we can see in the image, the result is 10000100 and the bits whose two inputs are =1 XOR results in 0.
Operators with Assignment
The operators with assignment perform the same logical operations that we saw before but their result is stored in the operand that precedes to operator.
The following expression performs the logical AND operation between the variable “a” and the variable or value assigned after the operator and the result is returned in “a”.
Rotation Operators
The rotation operators are “< < ” and “> > “.
These operators shift the data of a variable by “n” bits to the left or the right, respectively.
In the following expression, the operator shifts the data stored in “a” 5 bits to the left.
Example
In this example, we will assign the value 0b000001 to the variable “a” and then shift 1 bit to the left in a for loop and output the resulting value in the command console. This cycle is repeated 8 times
void main()
{
unsigned char a = 0b00000001;
unsigned char c;
for ( int bit=0;bit!=8;bit++) {
printf ("%i\n", a );
a=a<<1;
}
}
In the following image, we see the result with the decimal values corresponding to each position of the bits in an unsigned character.
Bit Masking
In certain cases, such as when we define multiple control flags grouped in a single register, we only need to know or change the value of one or more bits, not the entire register.
To get the status of one or more specific bits, we need to define a mask that sets only the bits of the elements whose value we want to know to 1 and apply the AND operation.
For example, if we want to get the value of bits 0 and 2 of variable “a”, we need to define the following mask and perform the AND operation.
In this case, only the status of bits 0 and 2 will be returned as a result, the remaining bits will have the value =0, regardless of what value they have “a”.
To change the value, we have to apply the OR operation between the mask with the bits we want to set to 1 and the variable we want to change. If we want to set it to 0, we must invert the mask as shown below and apply the AND operation.
Example
In this example, we use bit masking to create a simple and practical converter from decimal numbers to a string with its binary representation.
For this conversation we will use 8 masks, one for each bit, but to make the programming more practical and clearer, we will first use the mask 10000000 and then move one bit to the right in each cycle of the loop. In this way, we will get the following 8 masks that we need.
01000000
00100000
00010000
00001000
00000100
00000010
00000001
The converter consists of a for loop with 8 cycles, in each of which, it queries the status of the corresponding bit. This is done by a AND operation between the data to be converted and the corresponding mask.
If the result of the operation in “c” is 0, output this value with the printf() function. Otherwise, if the value of the bit is 1, it will be printed in the command console.
Below is the code for this handy converter.
In the following image, we see below the result of the conversion for the number 143.
Conclusion
In this Linux Hint article, we have explained each of the logical and rotation operators that the C language provides for bitwise processing. For each of these operators, we have created a section showing the symbol used for that operatorone description and a practical example with code snippets and images for each. We have also included a section dealing with bit masking and what is an addition, which is completely related to logical operations of this type.