|
Bit Manipulations |
|
We learned in the previous lesson that, when you declare a variable, the compiler reserves an amount of space in memory for that variable. Indeed, as we learned when studying bytes and words, a declared variable occupies space that resembles a group of small boxes.
Bit manipulation or a bit related operation allows you to control how values are stored in bits. This is not an operation you will need to perform very often, especially not in the early stages of your Object Pascal journey. Nevertheless, bit operations (and related operators) are present on all GUI or application programming environments, so much that you should be aware of what they do or what they offer. At this time, you should (must) be aware of what a bit, byte, and a word are, as we saw in the previous lesson.
|
Bits Operators: The Bitwise not Operator |
|
One of the operations you can perform on a bit consists of reversing its value. That is, if a bit holds a value of 1, you may want to change it to 0 and vice-versa. This operation can be taken care of by the bitwise
not operator.
Bitwise not is a unary operator that must be placed on the left side of its operand as in
not Value
To perform this operation, the compiler considers each bit that is part of the operand and inverts the value of each bit from 1 to 0 or from 0 to 1 depending on the value the bit is holding. This operation can be resumed in the following table:
|
Consider a number with a byte value such as 248. In Appendix C, we define how to convert numbers from one system to another (this could be a good time to review or study Appendix C). Based on this, the binary value of decimal 248 is 1111 1000 (and its hexadecimal value is 0xF8). If you apply the bitwise not operator on it to reverse the values of its bits, you would get the following result:
|
Value |
1 |
1 |
1 |
1 |
1 |
0 |
0 |
0 |
~Value |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
|
|
|
Comparing Bits: The Bitwise and Operator |
|
Bitwise and is a binary operator that uses the following syntax
Operand1 and Operand2
This operator considers two values and compares the bit of each with the corresponding bit of the other value. If both corresponding bits are 1, the comparison produces 1. Otherwise, that is, if either bit is 0, the comparison produces 0. This comparison is resumed as follows:
|
Bit1 |
Bit2 |
Bit1 and Bit2 |
0 |
0 |
0 |
1 |
0 |
0 |
0 |
1 |
0 |
1 |
1 |
1 |
|
Imagine you have two byte values represented as 187 and 242. Based on Appendix C, the binary value of decimal 187 is 1011 1011 (and its hexadecimal value is 0xBB). The binary value of decimal 242 is 1111 0010 (and its hexadecimal value is 0xF2). Let’s compare these two values bit by bit, using the bitwise AND operator:
|
|
Binary |
Decimal |
N1 |
1 |
0 |
1 |
1 |
1 |
0 |
1 |
1 |
187 |
N2 |
1 |
1 |
1 |
1 |
0 |
0 |
1 |
0 |
242 |
N1 and N2 |
1 |
0 |
1 |
1 |
0 |
0 |
1 |
0 |
178 |
|
Most of the times, you will want the compiler to perform this operation and use the result in your program. This means that you can get the result of this operation and possibly display it on the console. The above operation can be performed by the following program:
|
program Project1;
{$APPTYPE CONSOLE}
const N1 = 187;
const N2 = 242;
begin
Writeln(N1, ' and ', N2, ' = ', (N1 and N2));
Write('Press any key to continue...');
Readln;
end.
This would produce:
187 and 242 = 178
Press any key to continue...
Comparing Bits: The Bitwise or Operator |
|
You can perform another type of comparison on bits using the bitwise or operator. Its syntax is:
Value1 or Value2
Once again, the compiler compares the corresponding bits of each operand. If at least one of the equivalent bits is 1, the comparison produces 1. The comparison produces 0 only if both bits are 0. This operation is resumed as follows:
|
Bit1 |
Bit2 |
Bit1 or Bit2 |
0 |
0 |
0 |
1 |
0 |
1 |
0 |
1 |
1 |
1 |
1 |
1 |
|
Once again, let’s consider decimals 187 and 242. Their bitwise OR comparison would render the following result:
|
|
Binary |
Decimal |
N1 |
1 |
0 |
1 |
1 |
1 |
0 |
1 |
1 |
187 |
N2 |
1 |
1 |
1 |
1 |
0 |
0 |
1 |
0 |
242 |
N1 or N2 |
1 |
1 |
1 |
1 |
1 |
0 |
1 |
1 |
251 |
|
You can also let the compiler perform the operation and produce a result. Here is an example:
|
program Project1;
{$APPTYPE CONSOLE}
const N1 = 187;
const N2 = 242;
begin
Writeln(N1, ' or ', N2, ' = ', (N1 or N2));
Write('Press any key to continue...');
Readln;
end.
This would produce:
187 or 242 = 251
Press any key to continue...
Comparing Bits: The Bitwise-Exclusive xor Operator |
|
Like the previous two operators, the bitwise-exclusive xor operator performs a bit comparison of two values. It syntax is:
Value1 xor Value2
The compiler compares the bit of one value to the corresponding bit of the other value. If one of the bits is 0 and the other is 1, the comparison produces 1. In the other two cases, that is, if both bits have the same value, the comparison produces 0. This operation is resumed as
follows:
|
Bit1 |
Bit2 |
Bit1 xor Bit2 |
0 |
0 |
0 |
1 |
0 |
1 |
0 |
1 |
1 |
1 |
1 |
0 |
|
We will again consider decimals 187 and 242. Their bitwise-exclusive xor comparison would render the following result:
|
|
Binary |
Decimal |
N1 |
1 |
0 |
1 |
1 |
1 |
0 |
1 |
1 |
187 |
N2 |
1 |
1 |
1 |
1 |
0 |
0 |
1 |
0 |
242 |
N1 xor N2 |
0 |
1 |
0 |
0 |
1 |
0 |
0 |
1 |
73 |
|
If the compiler performs this operation, it can produce a result as in the following example:
|
program Project1;
{$APPTYPE CONSOLE}
const N1 = 187;
const N2 = 242;
begin
Writeln(N1, ' xor ', N2, ' = ', (N1 xor N2));
Write('Press any key to continue...');
Readln;
end.
This would produce:
187 xor 242 = 73
Press any key to continue...
Bit Shift Operators: The Left Shift shl |
|
In the previous lesson, we learned that bits are aligned in some consecutive manner to store data as needed. One operation you can perform on such bits consists of moving bits in a direction of your choice.
Object Pascal provides the left shift operator represented with shl and its syntax is:
Value shl ConstantInteger
The left shift operator, shl, is a binary operator whose right operand must be a constant integer. When performing the operation, the compiler would “push” Value’s bits to the left by the number of
ConstantInteger. The number of ConstantInteger bits on the left side of Value would disappear. The bits on the left side of Value would replace them. After moving to the left, the space left by the most right bits would be filled with 0 bits.
Imagine you have a variable named Value and whose value is 42. The binary value of 42 is 0010 1010. Imagine you want to shift Value to the left by 2 bits. You would proceed as follows:
|
|
|
0 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
42 Shifted to the left by 2 bits << 2 |
0 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
0 |
0 |
|
The resulting binary number is 1010 1000 and its decimal value is 168. This can also be illustrated in the following program:
|
program Project1;
{$APPTYPE CONSOLE}
const Value = 42;
begin
Writeln(Value, ' Shifted Left by 2 = ', Value shl 2);
Write('Press any key to continue...');
Readln;
end.
This would produce:
42 Shifted Left by 2 = 168
Press any key to continue...
Bit Shift Operators: The Right Shift shr |
|
As opposed to the left operator, the right shift moves bits to the right by a natural number. Everything is done as for the left shift except that the concept is applied to the opposite direction.
Therefore, if you shift 42 to the right, the binary result would be 0000 1010, which is equivalent to 10:
|
program Project1;
{$APPTYPE CONSOLE}
const Value = 42;
begin
Writeln(Value, ' Shifted Right by 2 = ', Value shr 2);
Write('Press any key to continue...');
Readln;
end.
This would produce:
42 Shifted Right by 2 = 10
Press any key to continue...