Comparing Bits: The Bitwise OR Operator |
|
You can perform another type of comparison on bits using the bitwise OR operator that is represented by |. Its syntax is:
Value1 | 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:
|
|
Once again, let’s consider decimals 187 and 242. Their bitwise OR comparison would render the following result:
|
|
You can also let the compiler perform the operation and produce a result. Here is an example:
|
#include <iostream> using namespace std; main() { const int N1 = 187; const int N2 = 242; cout << N1 << " | " << N2 << " = " << (N1 | N2) << "\n\n"; return 0; } This would produce: 187 | 242 = 251
Comparing Bits: The Bitwise-Exclusive XOR Operator ^
|
Like the previous two operators, the bitwise-exclusive OR operator performs a bit comparison of two values. It syntax is:
Value1 ^ 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:
|
|
We will again consider decimals 187 and 242. Their bitwise-exclusive XOR comparison would render the following result:
|
|
If the compiler performs this operation, it can produce a result as in the following example:
|
#include <iostream> using namespace std; main() { const int N1 = 187; const int N2 = 242; cout << N1 << " ^ " << N2 << " = " << (N1 ^ N2) << "\n\n"; } |
This would produce:
|
187 ^ 242 = 73
Bit Shift Operators: The Left Shift <<
|
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.
C++ provides the left shift operator represented with << and its syntax is:
Value << ConstantInteger
The left shift operator, <<, 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 (you are probably asking, "Why the hell do I need to know
this?" and my answer is, "I have no idea" but you ain't got
no choice; ain't no one else gonna learn this stuff for you).
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 1*27
+ 0*26 + 1*25 + 0*24 + 1*23 + 0*22
+ 0*21 + 0*20 = 1*128 + 0*64 + 1*32 + 0*16 + 1*8 + 0*4 +
0*2 + 0*1 = 128 + 0 + 32 + 0 + 8 + 0 + 0 + 0 = 128 + 32 + 8 = 168
This can also be illustrated in the following program:
|
#include <iostream> using namespace std; main() { const int Value = 42; cout << Value << " << 2 = " << (Value << 2) << "\n\n"; } |
42 << 2 = 168
Bit Shift Operators: The Right Shift >>
|
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 opposed
direction.
Therefore, if you shift 42 to the right, the binary result would be 0000 1010, whose decimal value is 10. |
Inline Assembly
|
Introduction
|
All the variables that we have used so far were
declared in, and passed to, the random memory (RAM). Once a variable is
declared and “put” in the memory, whenever it is involved in a
calculation or assignment, the microprocessor sends a request to the
memory to retrieve the value of the variable.
The Central Processing Unit (CPU), also called the
microprocessor, has its own memory. The microprocessor is made of memory
cells called registers. Unlike the memory in the RAM, the access of the
memory in the microprocessor is more precise; so precise that the
registers are referred to by using their names. Some of the most commonly
used registers (also called general purpose registers) are called EAX, EBX,
ECX, EDX, ESI, etc. These registers are mostly used in the Assembly
Language for low-level programming.
Most modern compilers allow you to include Assembly
Language code in your program. Using this feature, you can write a section
or sections of Assembly language. When Assembly is included in your C++
program, it is referred to as Inline Assembly.
|
Passing Values to Registers
|
Using registers allows the programmer to write
assignments directly destined for the microprocessor. The assignments and
operations in the Assembly language are called instructions. When
instructions are used by registers, the processing of the program is fast
because the microprocessor does not have to retrieve the values of the
variables in the RAM; these values, since existing in the registers, are
readily available.
A section that has Assembly code starts with __asm
followed by some other techniques. When the compiler encounters this
keyword, it knows that the subsequent code would be in Assembly language
and it would treat it accordingly. For example, instead of performing a
calculation in the RAM, the following program will assign values to two
integer variables, namely Number1 and Number2, then it calculate their sum
of those two numbers and stores the result in another variable called
Result. After the calculation, the Assembly section sends the result back
to the C++ compiler to display the variables and their values:
|
#ifdef __BORLANDC__ #pragma argsused #endif #include <iostream> using namespace std; int main( int argc, char * argv[] ) { int Number1, Number2, Result; __asm { MOV Number1, 248 // Initialize Number1 MOV Number2, 405 // Initialize Number2 MOV EAX, Number1 // Put the value of Number1 in the EAX register ADD EAX, Number2 // Add the value of Number2 to the content of EAX MOV Result, EAX // Put the content of EAX into Result } // That's it cout << "Number1 = " << Number1 << endl; cout << "Number2 = " << Number2 << endl; cout << "\nAfter adding Number1 to Number2," << endl; cout << "Result = " << Result << endl; return 0; } |
This would produce:
umber1 = 248 Number2 = 405 After adding Number1 to Number2, Result = 653
No comments:
Post a Comment