How2Lab Logo
tech guide & how tos..

Low Level Programming In C

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.

Register Variables

Earlier, we have seen that C supports four different storage classes, viz. 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 register 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 because a register variable does not have a l-value.

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 1s 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 a hexadecimal operand in a word of 16 bits.

  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:

  &	- bitwise AND operator
  |	- bitwise OR operator
  ^	- 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.

Results of bitwise operations
xyx & yx ^ yx | y


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)

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

x & y :
	x = 0101 1010 1011 0110
	y = 0110 0001 1100 1101
    x & y = 0100 0000 1000 0100
	  = 0x4084 (in hex)

x ^ y :
	x = 0101 1010 1011 0110
	y = 0110 0001 1100 1101
    x ^ y = 0011 1011 0111 1011
	  = 0x3B7B (in hex)

x | y :
	x = 0101 1010 1011 0110
	y = 0110 0001 1100 1101
    x | 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 an unsigned integer 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.


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 shifts the bits by six positions
              The vacant bit positions due to shift get filled up by zeros

 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;


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 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, if X is an unsigned hexadecimal quantity whose content is 0x65DF, then to extract right-most of bits to a new word Y a mask of 0x7F is used with the operand X.

  Y = X & 0x7f;

  X    = 0110 0101 1101 1111
  mask = 0000 0000 0111 1111
  Y    = 0000 0000 0101 = 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 left-most 6 bits retain their original values.

  Y = X | 0x3ff;

  X    = 0110 0101 1101 1111
  mask = 0110 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 left-most 9 bits are to be copied and the remaining 7 bits are to be inverted.

  Y = X ^ 0x1ff;

  X    = 0110 0101 1101 1111
  mask = 0000 0000 0111 1111
  Y    = 0110 0101 1010 0000
         <--- A ---><--B -->
         A. Same as original; B. Inverted bit pattern

Example Codes

/* Binary to Decimal Conversion */

#include <stdio.h>
	long unsigned bin, store, dec=0, pos = 0, digit;

	printf("\nEnter a Binary Number: ");
	scanf("%ld",&bin); fflush(stdin);

	store = bin;
		digit = bin % 10;
		dec += digit << pos;
		bin /= 10;

	printf("The Decimal equivalent of Binary %Id is %ld\n\n", store, dec); 

/* Decimal to Binary Conversion */

#include <stdio.h>
	int i, j, cnt, nbits;
	unsigned mask; 

	printf("\nEnter an Integer value: ");
	scanf("%d", &i); fflush(stdin);

	nbits = (8 * sizeof(int));
	mask = 0x1 << (nbits - 1); 
	for(cnt = 0; cnt < nbits; cnt++) 
		j = (i & mask)? 1: 0;
		mask >>= 1; 


Write a C program to encode and decode the contents of a text file according to the following scheme:

  1. Encode each character by computing bit-wise AND (&) of the 8-bit representation of the character with a mask called encryption key.
  2. Decode an encoded character by computing bit-wise OR (|) of the encoded byte with the complement of the encoding key.

The program should support following operations:

  1. Create a text file by reading lines from the keyboard.
  2. The original text is to be stored in a file.
  3. Ask the user to supply the encryption key and then encode the text file. The encoded text is to be stored in the same file.
  4. Retrieve the text file that has been saved after decoding, provided the user has correctly supplied the encoding key.

The program should be menu driven with adequate options to the user.

Repeat the problem mentioned above by using a bit-wise exclusive operation for both encoding and decoding. What will be the value of decoding key for a given encoding key?

Buy Domain & Hosting from a trusted company
Web Services Worldwide | Hostinger
About the Author
Rajeev Kumar
CEO, Computer Solutions
Jamshedpur, India

Rajeev Kumar is the primary author of How2Lab. He is a B.Tech. from IIT Kanpur with several years of experience in IT education and Software development. He has taught a wide spectrum of people including fresh young talents, students of premier engineering colleges & management institutes, and IT professionals.

Rajeev has founded Computer Solutions & Web Services Worldwide. He has hands-on experience of building variety of websites and business applications, that include - SaaS based erp & e-commerce systems, and cloud deployed operations management software for health-care, manufacturing and other industries.

Refer a friendSitemapDisclaimerPrivacy
Copyright © All rights reserved.