Showing posts with label 11. LOW-LEVEL PROGRAMMING. Show all posts
Showing posts with label 11. LOW-LEVEL PROGRAMMING. Show all posts

Saturday, January 23, 2010

11.2.5 THE BITWISE ASSIGNMENT OPERATORS

C also contains the following bitwise assignment operators.
             &=       ^=       |=       <<=         >>=

These operators combine the preceding bitwise operations with ordinary assignments.The left operand must be an assignable integer-type identifier (e.g., an integer variable), and the right operand must be a bitwise expression. The left operand is interpreted as the first operand in the bitwise expression. The value of the bitwise expression is then assigned to the left operand. For example, the expression
a &= 0x7f is equivalent to a = a & 0x7f.

The following program displays the bit pattern corresponding to a signed decimal integer.

#include < stdio.h >


main ()
{
int a, b, m, count, nbits;
unsigned mask;


/*determine the word size in bits and set the initial mask*/
nbits = 8* sizeof (int);
m = 0x1 << (nbits - 1);     /*place 1 in leftmost position*/


/*main loop*/
do {
/*read a signed integer*/
printf("\n\nEnter an integer value (0 to stop): ", a);
scanf("%d", &a);


/*output the bit pattern*/
mask = m;
for (count = 0; count <= nbits; count++)  {
   b = (a & mask) ? 1 : 0;    /*set the display bit on or off*/
   printf("%x", b);               /*print display bit*/

   if (count % 4 == 0)
       printf(" ");      /*blank space after every 4th digit*/
   mask >>= 1;  /*shift mask 1 position to the right*/

}

}


The program is written so that it is independent of the integer word size. Therefore it can be used on any computer.            

Wednesday, January 20, 2010

11.2.4 THE SHIFT OPERATORS

The two bitwise shift operators are shift left (<<) and shift right (>>). Each operator requires two operands.The first is an integer type operand that represents a bit pattern to be shifted. The second is an unsigned integer that indicates the number of displacements (i.e., whether the bits in the first operand will be shifted by 1 bit position, 2 bit positions, 3 bit positions, etc.). This value cannot exceed the number of bits associated with the word size of the operand.

Suppose a is an unsigned integer variable whose value is 0x6db7. The expression
b = a << 6;

will shift all bits of a six places to the left and assign the resulting bit pattern to the unsigned integer variable b. The resulting value of b will be 0x6dc0.


 
All of the bits originally assigned to a are shifted to the left 6 places..The rigtmost 6 bits positions are filled with 00 0000.

11.2.3 MASKING

Masking is a process in which a given bit pattern is transformed into another bit pattern by means of a logical bitwise operation.The original bit pattern is one of the operands in the bitwise operation.The second operand called the mask, is a specially selected bit pattern that brings about the desired transformation.

There are several kinds of masking operations.For example, a portion of a given bit pattern can be copied to a new word, while the remainder of the new word is filled with 0s.Thus, part of the original bit pattern will be "masked off" from the final result. The bitwise and operator is used (&) is used for this type of masking operation as illustrated below.

Suppose a is an unsigned integer variable whose value is 0x6db7.Extract the rightmost 6 bits of this value and assign them to the unsigned integer variable b. Assign 0s to the 10 leftmost bits of b.

To carry out this operation, we write the bitwise expression
b= a & 0x3f;

The second operand 0x3f will serve as the mask. Thus the resulting value of b will be 0x37.

The validity of this result can be established by examining the corresponding bit patterns.

             a = 0110 1101 1011 0111
       mask = 0000 0000 0011 1111
                  ---------------------------------
             b = 0000 0000 0011 0111
               = 0x37
The mask prevents the leftmost 10 bits from being copied from a to b.

Suppose once again a is an unsigned integer variable whose value is 0x6db7.Now extract the leftmost 6 bits of this value and assign them to the unsigned integer variable b.Assign 0s to the 10 rightmost bits of b.

To carry out this operation, we write the bitwise expression
b= a & 0xfc00;

Another type of masking allows a portion of a given bit pattern to be copied to a new word, while the remainder of the new word is filled with 1s.The bitwise or (|) operator is used for this purpose.

A portion of a given bit pattern can be copied to a new word, while the remainder of the original bit pattern is inverted within the new word.The bitwise exclusive or (^) operator is used for this type of masking.

Thursday, January 14, 2010

11.2.2 THE LOGICAL BITWISE OPERATORS

There are three logical bitwise operators: bitwise and (&), bitwise or (|), bitwise exclusive or (^). Each of these operators requires two integer-type operands.The operations are carried out independently on each pair of corresponding bits within the operands.Thus, the least significant bits (i.e. the rightmost bits) within the two operands will be compared. The results of these comparisons are:
1. A bitwise and expression will return a 1 if both bits, have a value of 1 (i.e., if both bits are true). Otherwise,  it will return a value of 0.
2.  A bitwise exclusive or expression will return a 1 if one of the bits has a value of 1 (i.e., if one bit is true, the other is false). Otherwise,  it will return a value of 0.
3. A bitwise or expression will return a 1 if one or more bits, have a value of 1 (i.e., if one or both bits are true). Otherwise,  it will return a value of 0.

The results are summarized in the following table.


b1

b2

b1&b2

b1^b2

b1|b2

1

1

1

0

1

1

0

0

1

1

0

1

0

1

1

0

0

0

0

0

Wednesday, January 13, 2010

11.2.1 THE ONE'S COMPLEMENT OPERATOR

The one's complement operator (~) is a unary operator that causes the bits of its operand to be inverted (i.e., reversed) so that 1s become 0s and 0s become 1s. This operator always precedes its operands.The operand must be an integer-type quantity (including integer, long, short, unsigned, char, etc.).

Consider the simple C program shown below.


#include


main()
{
unsigned i = 0x5b3c;


printf("hexadecimal values: i = %x  ~i = %x\n", i, ~i);
printf("decimal equivalents: i = %u  ~i = %u\n", i, ~i);
}

Executing this program on a computer with a 16-bit word size results in the following output.


hexadecimal values: i = 5b3c    ~i = a4c3
decimal equivalents: i = 23356  ~i = 42179

To understand these results, first consider the bit patterns corresponding to the values for i and ~i.

i = 0101 1011 0011 1100
~i = 1010 0100 1100 0011

Therefore the decimal equivalents are

i= 23356 and ~i= 42179

11.2 BITWISE OPERATIONS

Some applications require the manipulation of individual bits within a word of memory. Assembly language or machine language is normally required for operations of this type. However, C contains several special operators that allow such bitwise operations to be carried out easily and efficiently.These bitwise operators can be divided into three general categories: the one's complement operator, the logical bitwise operators and the shift operators. C also contains several operators that combine bitwise operations with ordinary assignment.Each category is discussed separately below.

11.1 REGISTER VARIABLES

In chapter 6 we mentioned that there are four different storage class specifications in C, and we discussed about three of them- automatic, external and static- in detail. We now turn our attention to the last of these, which is the register storage class.

Registers are special storage areas within the computer's central processing unit. The actual arithmetic and logical operations that comprise a program are carried out within these registers.Normally, these operations are carried out by transferring information from the computer's memory to these registers, carrying out the indicated operations, and then transferring the results back to the computer's memory. This general procedure is repeated many times during the course of a program's execution.

The register and automatic storage classes are closely related.In particular, their visibility (i.e. their scope) is the same. Thus, register variables, like automatic variables, are local to the function in which they are declared. Furthermore, the rules governing the use of register variables are the same as those for automatic variables, except that the address operator(&) cannot be applied to register variables.

The program presented below is a variation of that shown in Section 6.4, for generating a series of Fibonacci numbers.

/* calculate the first 23 Fibonacci numbers 10,000,000 times, to illustrate the use of register variables*/




#include < stdio.h >
#include < time.h >
 
long int fibonacci  (int count);


main()
{
time_t start, finish;  /* start and finish times*/
int count, n=23;
long int loop, loopmax = 1000000;
register int f , f1, f2;

/* tag the starting time*/
time(&start);

/* do multiple loops*/
for (loop=1; loop <= loopmax; ++loop)  {
f1=1;
f2=1;
 
/*generate the first n Fibonacci numbers*/
for (count=1;count <= n;++count)   {
f= (count < 3)? 1 : f1+f2;
f2=f1;
f1=f;
}
}

/* adjust the counter and tag the completion time*/
--count;
time(&finish);

/*display the output*/
printf ("i= %d  F= %d\n", count, f);
printf ("elapsed time: %0.1f seconds", difftime (finish, start));
}


The program includes three integer variables that have the register storage class. Only 23 Fibonacci numbers will be calculated, since the Fibonacci numbers are represented as ordinary integer variables (higher Fibonacci numbers will generate an integer overflow).The calculation of the Fibonacci numbers is repeated 10,000,000 times, in order to obtain a reasonably accurate assessment of the time required to execute the program.

The variables start and finish are of type time_t, as defined in the header file time.h.The program also makes use of the library function difftime, which returns the time difference defined  by the variables finish and start.



When executed on a Pentium-class desktop computer, the following results were obtained:

i=23  F=28657
elapsed time: 37 seconds

If the program is rerun without the register declaration (i.e., if the variables f, f1 and f2 are declared as ordinary integer variables), the output is essentially the same.When run with an older desktop computer, however the use of register class resulted in a 36 percent reduction in computer time.

Tuesday, January 12, 2010

11. LOW-LEVEL PROGRAMMING

From the materials presented in the first 10 chapters, it should be clear that C is a full fledged, high-level programming language. However C also possesses certain "low-level" features that allow the programmer to carry out operations normally available only in assembly language or or machine language.For example, it is possible to store the values of certain variables within the central processing unit's registers.This will usually speed up any computation associated with these values.

C also permits the manipulation of individual bits within a word.Thus, bits can be shifted to the left or the right, inverted (1s and 0s reversed), or masked (extracted selectively).Furthermore, C allows the bits within a word of memory to be organized into individual groups.This permits multiple data items to be packed within a single word.This chapter shows how to carry low-level operations in C.