Low Level Programming in C

Oracle Certification Program Candidate Guide


In addition to the high level language constructs, (data type and operators), C also supports low level programming features which enable the programmer to carry out bit-wise operations. These features are normally provided in assembly language or machine language. The bit level operations and register variables discussed in this section can be thought of as a bridge between high level programming constructs and assembly/machine language operations. Thus one can directly store and manipulate variables stored in the CPU registers and use that result in another subprogram.

13.1 REGISTER VARIABLES

Earlier in Chapter 6, we listed four different storage classes, static, auto, extern and register. As such, general purpose registers are special storage areas within the Central Processing Unit (CPU). The CPU registers are used for temporarily holding intermediate results generated by the Arithmetic Logic Unit (ALU). It also stores information that are transferred from the main memory of the computer for further processing, this reduces the traffic between CPU and RAM which inevitably leads to higher degree of efficiency.

In C, the content of register variables reside inside registers. A program that uses register variables execute faster since their values are stored inside the registers within the CPU rather than in the RAM. A variable can be declared of storage class type register by prefixing the variable declaration by the keyword register. For example,

register int cnt=0;

However, only a few register variables can effectively be used in a C function. The exact number of register variable declarations possible in a function is machine dependent. The scope of a register variable is identical to that of auto type variables.

It is not always the case that a variable defined to be of storage class registers has to be a register variable only. The declaration is valid only when the requested register space is available, otherwise the variable declared to have storage class register, will be treated as automatic variable only. The important distinction between an automatic and register variable is that a register variable can never be preceded by the unary operator & since a register variable does not have a l-value.

13.2 BITWISE OPERATORS

C allows the manipulation of individual bits within a word(register) of computer memory. Such bit level operations enable programmers to develop machine-level applications easily and efficiently.

Operators such as one’s complement operator, the logical operator, and shift operators can be used in combination with other operators in an expression.

The one’s complement operator (~)

The unary operator (the tilde symbol ~) complements each individual bit of its operand so that 1’s become 0’s and 0’s become 1’s. The operator precedes the operand, where the operand is always an integer quantity ( an unsigned octal or unsigned hexadecimal number). In the following example, this operator has been used to find one’s complement of an hexadecimal operand in a word of 16 bits,

Example 13.1 :

Expression Value

~0xc5 0xff3a

0xc5 = 0000 0000 1100 0101

by inverting each bit we get,

1111 1111 0011 1010 =0xff3a

Logical bitwise operator

The logical bitwise operators are ,

a. & - bitwise AND operator

b. | - bitwise OR operator

c. ^ - bitwise exclusive OR operator

They operate on two integer operands, taking each individual bit into consideration from the pair of bit patterns according to the corresponding position of that bit among the two operands.

The operations on individual bits of two operands starts from the rightmost or the least significant bit. The result of the operation between a bit (let us say x ) of one operand with a bit (let us call it y) of the other, depends on the logical bitwise operator used. The following table gives the result of applying these operators to one bit operands x and y.

x

y

x & y

x ^ y

x | y

1

1

1

0

1

1

0

0

1

1

0

1

0

1

1

0

0

0

0

0

Table 13.1 : Results of bitwise operations.

Example 13.2 :

Suppose x and y are two integer variables having values 0x5AB6 and 0x61CD respectively. The result of applying bitwise operators are as follows,

5 A B 6

x = 0x5AB6 = 0101 1010 1011 0110 (in binary)

~x = 1010 0101 0100 1001 = 0xA549 (in hex)

So,

x & y = 0101 1010 1011 0110 (x)

0110 0001 1100 1101 (y)

0100 0000 1000 0100

= 0x4084 (in hex)

x ^ y = 0101 1010 1011 0110 (x)

0110 0001 1100 1101 (y)


0011 1011 0111 1011

= 0x3B7B (in hex)

x | y = 0101 1010 1011 0110 (x)

0110 0001 1100 1101 (y)

0111 1011 1111 1111

= 0x7BFF (in hex)

Shift operator

The shift left (<<) and shift right (>>) are two bitwise shift operator. Each of them requires two operands, the first one is an integer number that represents the bit pattern to be shifted. The second operand corresponds to a number that indicates the amount of displacement (i.e. number of bits to be shifted). The two operators right or left shift decide the direction in which displacement takes place.

Example 13.3 :

For example, if X is an integer quantity with value 0x65CF then the following statement ,

Y = X << 5 ;

left shifts the bits by five positions. The vacant bit positions due to shift get filled up by zeros.

X = 0110 0101 1100 1111


Y = 1011 1001 1110 0000

Y= X >> 6;

(right shift by six position)

X = 0110 0101 1100 1111


Y = 0000 0001 1001 0111

Bitwise Assignment Operators

The following bitwise assignment operators are also available,

&=, ^=, |=, <<=, >>=

The usage of these operators can be readily understood by considering the following assignment expression,

X=X & Y;

This expression can also be represented using the bitwise assignment operator as,

X &= Y;

1. Consider an unsigned integer a whose value is (hexadecimal) 0xb3d7. Show the corresponding bit pattern for a and evaluate each of the following bitwise expressions. In each case show the resulting bit pattern and then the equivalent hexadecimal value. Assume that a is stored in a 16-bit word.

i) compute bitwise and, or and exclusive or operations with a and 0x4f05.

ii) compute ~a and then perform bitwise and, or and exclusive or operations with 0x4f05.

iii) a >> 5

iv) a <<>

v) a & ~a

vi) a ^ ~a

vii) a & ~0x4f05 <<>

viii) (a & ~0x40f5) <<>

ix) a | ~0x4f05 <<>

x) a | 0x4f05 <<>

2. Suppose that v is a signed, 16 bit integer quantity having hexadecimal value 0x4a3d. Evaluate each of the following shift expressions.

(i) v << style=""> (ii) v >> 4


13.3 MASKING

The masking operation transforms the bit patterns of an operand with the help of a specially selected bit pattern called mask, where two operands are separated by an appropriate logical bitwise operator.

Different types of masking operations

To copy a portion of a bit pattern to a new word, one needs to mask remaining bits in the source operand with the help of the logical bitwise operator &. For example, suppose X is a unsigned hexadecimal quantity whose content is 0x65DF. To extract rightmost of bits to a new word Y a mask of 0x7F is used with the operand X.

Example 13.4 :

Y = X & 0x7f ;

X = 0110 0101 1101 1111

mask = 0000 0000 0111 1111

Y = 0000 0000 0101 1111 = 0x5f

( last 7 bit copied as it is )

Another type of masking operation copies certain number of bits to a new word, while remaining bits in the new word are filled with 1s. This is achieved using OR logical bitwise operator. Consider the same two variable X and Y to understand the following example where leftmost 6 bits retain their original values.

Example 13.5 :

Y = X | 0x3ff ;

X = 0110 0101 1101 1111

mask = 0000 0011 1111 1111

Y = 0110 0111 1111 1111 = 0x67ff

A portion of a given bit pattern can be copied to a new word, while rest of the original bits are inverted within the new word. This is achieved using exclusive OR logical bitwise operator. Consider X and Y, where leftmost 9 bits are to be copied and the remaining 7 bits are to be inverted.

Example 13.6 :

Y = X ^ 0x1ff ;

X = 0110 0101 1101 1111

mask = 0000 0000 0111 1111

Y = 0110 0101 1010 0000

same as original inverted bit pattern

bit pattern

3. Select a suitable mask and the appropriate masking operation for each of the following problems.

a) Given a 16-bit unsigned integer variable x (assume that bit 0 is the rightmost bit),

i) modify the even bits (0,2,4,...,14) and retain the odd bits (1,3,5, .... 15).

ii) copy the even bits and place them in the odd bit locations.

(b) Set the most significant bit (the leftmost bit) of an 8-bit character represented by the variable c to zero.


13.4 EXAMPLE OF BITWISE OPERATIONS

Example 13.7 :

/* binary to decimal conversion */

# include

main()

{

long unsigned bin,store, dec=0, pos=0, digit;

printf(“Enter the binary number :”);

scanf(“%ld”,&bin);

fflush(stdin);

store=bin;

while(bin)

{

digit=bin % 10;

dec += digit <<>

pos++;

bin /= 10;

}

printf(“The decimal equivalent to binary %ld is %ld\n\n”,store,dec);

}

/*decimal to binary conversion */

# include

main()

{

int i,j,cnt,nbits;

unsigned mask;

nbits=(8 * sizeof(int));

mask=0x1 << (nbits - 1);

printf(“\nEnter an integer value :”);

scanf(“%d”,&i);

fflush(stdin);

for(cnt=0; cnt <>

{

j=(i & mask)? 1 : 0;

printf(“%x”,j);

mask >>= 1;

}

printf(“\n”);

}

0 comments: