What are logical operators and how does bit-by-bit operations work in the C language?
What are logical operatorsNOT
, AND
, OR
, XOR
, in language C
?
I also did not understand these operators: ~
, &
, |
, ^
, >>
, <<
and the result in bits. I have the following code example:
#include <stdio.h>
#include <stdlib.h>
int main()
{
unsigned char x, y;
x = 44;
printf("x = %d\n", x);
y = ~x;
printf("~x = %d\n", y);
y = x & 67;
printf("x & 67 = %d\n", y);
y = x | 129;
printf("x | 129 = %d\n", y);
y = x ^167;
printf("x ^167 = %d\n", y);
y = x <<2;
printf("x <<2 = %d\n", y);
y = x >>2;
printf("x >>2 = %d\n", y);
system("pause");
return 0;
}
1 answers
Bitwise operations, bitwise operations or binary logic, usually refers to logical operations done with binary numbers. These operations range from operations AND
, OR
, NOT
, XOR
, NOR
, NAND
, simple bit shift , among other operations. It should be said that some of these operations mentioned here are groupings of other operations, such as NAND
, which is a grouping of a logic AND
with logic NOT
. There are also interesting things to be studied, such as Boole algebra (or Boolean algebra ) and De Morgan's theorems.
Operation NOT.
Operation NOT
(No), also called "negation" or "inversion", is the simplest of operations, as it consists of reversing the state of the bits. Take as an example the binary number 00111100
. After going through an operation NOT
becomes 11000011
. In some programming languages, such as C
, you use the ~
operator to reverse the bit State. The operation NOT
follows the truth table:
Let's take as an example the following code in C
:
unsigned char x, y;
x = 44;
printf("x = %d\n", x);
y = ~x;
printf("~x = %d\n", y);
This excerpt results in the following impression:
x = 44
~x = 211
You can check the size that a variable occupies in C
by calling the function sizeof(type)
. This function returns the size of the variable in bytes, so you have to multiply the result by 8 to get the value in bits.
printf("Tamanho do char é de %d bits e %d byte (s)\n", (sizeof(char) * 8), sizeof(char));
This excerpt results in the following print:
Tamanho do char é de 8 bits e 1 byte (s)
Because the char type in C
is an 8-bit variable, when assigning x = 44
what you are doing is assigning a variable that contains the value 00101100
. Or rather:
x = 44 é:
128| 64| 32| 16| 8| 4| 2| 1
0| 0| 1 | 0 | 1| 1| 0| 0
Therefore, we have 32 + 8 + 4 which is equivalent to the 44 already mentioned. But when you pass the operation NOT
, you reverse the state of these bits, getting:
x = 44 é:
0| 0| 1| 0| 1| 1| 0| 0
y = ~x é:
1| 1| 0| 1| 0| 0| 1| 1 Equivalente a 211
One thing that is interesting to note is that the inverse of 44 in an 8-bit variable is 211. An 8-bit variable stores 256 values, these values being from 0 to 255, so it can be said that when performing a negation, you get the remaining value at 255 (44 + 211 = 255).
Operation and.
The operation AND
(E), also called a "conjunction", has the symbol *
or .
and returns 1 when, and only when, all bits are 1 (or true). In the language C
this operation has the symbol &
between two variables. Operation AND
(or) is an operation that follows the following truth table:
Let's now take the following code snippet:
y = x & 67;
printf("x & 67 = %d\n", y);
This excerpt results in the following impression:
x & 67 = 0
x
it still equals 44, i.e. 00101100
in binary. When performing an operation AND
with 67 (01000011
in binary) what is actually being done is:
MSB (Most Significant Bit)
x & 67
0 AND 0 => 0
0 AND 1 => 0
1 AND 0 => 0
0 AND 0 => 0
1 AND 0 => 0
1 AND 0 => 0
0 AND 1 => 0
0 AND 1 => 0
LSB (Least Significant Bit)
00000000 binário => 0 decimal
Therefore, an operation AND
between 44 & 67
returns the number 0, printed on the line following.
Operation OR.
The operation OR
(or), also called "disjunction", has the symbol +
. This operation returns 1 when any of the bits is 1 and returns 0 when all the bits are 0. The operation OR
is an operation that follows the following truth table:
In the C language, the operator |
is used to perform an OR operation between two variables. As in the following code:
y = x | 129;
printf("x | 129 = %d\n", y);
This stretch results in the following impression:
x | 129 = 173
x
which is worth 44
, i.e. 00101100
in binary, is in a disjunction operation with 129
(10000001
in binary). When performing an operation OR
between 44
and 129
what is actually being done is:
MSB (Most Significant Bit)
x & 67
0 OR 1 => 1
0 OR 0 => 0
1 OR 0 => 1
0 OR 0 => 0
1 OR 0 => 1
1 OR 0 => 1
0 OR 0 => 0
0 OR 1 => 1
LSB (Least Significant Bit)
10101101 binário => 173 decimal
Therefore, an operation OR
between 44 & 129
returns the number 173
, printed on the next line.
Operation XOR.
The operation XOR
(or exclusive), also called " disjunction unique", is a logical operation between two operands that results in a true logical value if, and only if, exactly one of the operands has true value. It can be synthesized as a detector of differences between two logical operands. This operation follows the following truth table:
The XOR operation is an interesting way to exchange the value of two variables without needing a third, as demonstrated by the excellent answer given by Lucas Nunes in this question .
In the C language, the operator ^
is used to perform an operation XOR
between two variables. As in the following code:
y = x ^167;
printf("x ^167 = %d\n", y);
Which results in printing:
x ^167 = 139
Pois 44 (00101100) XOR 167 (10100111)
:
MSB (Most Significant Bit)
x ^ 167
0 XOR 1 => 1
0 XOR 0 => 0
1 XOR 1 => 0
0 XOR 0 => 0
1 XOR 0 => 1
1 XOR 1 => 0
0 XOR 1 => 1
0 XOR 1 => 1
LSB (Least Significant Bit)
10001011 binário => 139 decimal
Therefore, an operation XOR
between 44 & 167
returns the number 139
, printed on the next line.
Bit offset.
In the C
language, the operators >>
or <<
are used to bit shift between variables to right or left. Bit shifting, as the name already says, is a technique of shifting bits to one or more houses. An interesting feature of bit displacement is that it is possible to multiply or divide the value of that variable, but I will not go into details about this in this answer.
Bit shift works as follows, for example, when moving a variable x to the left:
int x = 1; // 0000 0001
int x0 = (x << 0); // 0000 0001 Não deslocado
int x1 = (x << 1); // 0000 0010
int x2 = (x << 2); // 0000 0100
int x3 = (x << 3); // 0000 1000
int x4 = (x << 4); // 0001 0000
int x5 = (x << 5); // 0010 0000
int x6 = (x << 6); // 0100 0000
int x7 = (x << 7); // 1000 0000
Now move right:
int x = 128; // 1000 0000
int x0 = (x >> 0); // 1000 0000 Não deslocado
int x1 = (x >> 1); // 0100 0000
int x2 = (x >> 2); // 0010 0000
int x3 = (x >> 3); // 0001 0000
int x4 = (x >> 4); // 0000 1000
int x5 = (x >> 5); // 0000 0100
int x6 = (x >> 6); // 0000 0010
int x7 = (x >> 7); // 0000 0001
I will not delve much into this technique, but I recommend that you read the excellent answer of Lucas Nunes in this question, from which I took the example above. But in the case of the code you provided in your question, what happens is:
y = x << 2;
printf("x <<2 = %d\n", y);
The code snippet above prints:
x <<2 = 176
Peas:
00101100 em binário é 44 em decimal
00101100 << 2
01011000 //Moveu 1 bit a esquerda
10110000 //Moveu 2 bits a esquerda
10110000 em binário => 176 decimal
y = x >> 2;
printf("x >>2 = %d\n", y);
The code snippet above print:
x >>2 = 11
Peas:
00101100 em binário é 44 em decimal
00101100 >> 2
00010110 //Moveu 1 bit a direita
00001011 //Moveu 2 bits a direita
00001011 em binário => 11 decimal
Applications.
Bit operations are often used when programming low level. You can configure microcontroller loggers and do code optimizations, for example. They are also used in encryption algorithms , because they are logical operations are less costly to the processor. In digital electronics, they are used at all times.