Beruflich Dokumente
Kultur Dokumente
Prerequisite:
To understand these new concepts in C, the basic knowledge of pointers in C and Internal Architecture of Microprocessor is required.
General-Purpose Registers
EU(Execution Unit of Microprocessor) has Eight 8-bit generalpurpose registers, AH, AL BH, BL CH, CL DH and DL These registers can be used individually for temporary storage of 8-bit data. Register pairs AH-AL, BH-BL, CH-CL, and DH-DL can be used together to form register AX, BX, CX, and DX and can be used to store 16-bit data words. The AL register is also called the Accumulator.
Segment Registers The 8086 microprocessor has Four Segment Registers: CS (Code Segment Register) DS (Data Segment Register) SS (Stack Segment Register) ES (Extra Segment Register) These registers are used to refer Segment part of Memory address. The 8086 microprocessor has Five Offset Registers: IP (Instruction Pointer or Program Counter) SP (Stack Pointer) BP (Base Pointer) SI (Source Index) DI (Destination Index) These registers are used to refer Offset part of Memory address.
Types of Pointers
Near Pointers Far Pointers Huge Pointers
Near Pointers: A Near Pointer is of 16-bits. It uses the current contents of the CS(Code Segment) register or DS(Data Segment) register for Segment part Whereas the offset part is stored in 16-bits NEAR pointer. Clearly this type of Pointer limits us to 64KB memory of a particular segment.
Far Pointers: A Far Pointer is of 32-bits long. This type of Pointer contains both segment and offset. By using it we can point to multiple segments so Limit of 216 = 26 X 210 = 64kb does not exist for Far Pointers Hence with Far Pointers we can address more than 64kb of data.
Huge Pointers: A Huge Pointer is of 32-bits long. This is same as Far pointer except one difference that here Segment: Offset address is always Normalized. So the offset always contains value from 0 to F For Example : an Address 500D : 9407 will be converted to 594D : 0007 as shown below:
Segment: 500D0 (0 is appended automatically ) + 9407 After Addition we get 594D7 Which is Normalized as 594D : 0007
The problem of Suspicious Pointer Conversion can be solved by using Type Casting as shown in the program given below: main() /* TYPEc.C */ { int i=10; float *p; p=(float *)&i; }
Now let us see another program which tries to refer the address which lies outside the DS(Data Segment) of our program.For achieving this we have to use Far Pointer as Given below:
main()
{
/* SCR.C */
How it Works ?
The address 0xB8000000L is a an address of the beginning of Colored VDU Memory Block. For Monochrome Adapter the address is 0xB0000000L. Each Character present on screen has TWO bytes corresponding to it in the VDU memory. The FIRST byte contains the ASCII Value of the character. The SECOND byte contains COLOR of that character. So if A is displayed on row -0 and column -0 on the screen then address 0xB8000000L contains ASCII value of A and address (0xB8000000L + 1) contains the COLOR of A Hence if One character requires TWO Bytes the One Screenful of characters will require 80 * 25 * 2 = 4000 Bytes .
/* SCRofA.C */
{
char far *screen = (char far *)0xB8000000L; int i; for ( i = 0 ; i <= 3999 ; i = i + 2) *(screen + i ) = A; } Note : What will happen if variable I is incremented one at a time ?
Purpose Video Display Diskette Services Communication Devices Keyboard Services Printer Services Memory size Time and Date
int86() Function
This function is used to make a Software Interrupt. Here int stands for Interrupt and 86 stands for 8086 family of Microprocessors. It has following Three arguments: Interrupt Number Two union variables
The First union variable refers to values passed and Second for values returned by the int86() function.
e.g. int86(16, &inregs, &outregs); Where
/* MEMsize.C */
#include dos.h /* union variables are declared in it */ main() { union REGS inregs, outregs; int memsize; int86(18, &inregs, &outregs); memsize = outregs.x.ax; printf(\n Total Memory (RAM) = %d,memsize); }
In this program we have not passed any values to the inregs because the Interrupt Number 18 does not require it, but it returns memory size in the register ax whose contents can be accessed by using outregs.x.ax, Where x is a variable of union variable REGS.
Let us see another program to print a TEXT at any Row and Column on the Screen..
/* Textrc.C */
#include dos.h /* union variables are declared in it */ main() { union REGS inregs, outregs; inregs.h.ah = 2; /* Service Number */ inregs.h.dh = 10; /* Row Number */ inregs.h.dl = 2; /* Column number */ int86(16, &inregs, &outregs); printf(\n Hello);
In this program, We have passed some values to the function int86(). Upon return from the function, the cursor is set to the position mentioned in the program. Hence depending upon the Service Number of the Interrupt, we have to pass and receive the values through inregs and outregs variables.
Pointers to Functions
As we know that Pointers can be used as Reference Variables to any of the Data types in C. Similarly Pointers can also be used to point C Functions. So if we know the functions address, we can point to it. In C, We can find the Address of any function. This Address then can be assigned to a Pointer.
Let us see the following program to Find Address of a function: main( ) /* p_fun.c */ { int display( ); printf ( \n Address of function display is %u, display); display( ); } display( ) { printf( \n In function display ); }
So from above program it is clear that we can find the Address of any function. Let us see following program in which Address of Function is assigned to a Pointer as given below: main( ) { int display( ); int (*fp)(); /* Declaration of Pointer to a Function */ fp = display; /* Assigning Address of Function to Pointer */ printf ( \n Address of function display is %u, display); (*fp)(); /* Invoking Function through Pointer Fp*/ } display( ) { printf( \n In function display ); } /*
p_fun2.c */
So from above program it is clear that we can call any function with the help of Pointers.. Let us see following program in which Address of a number of Functions is assigned to an array of Pointers as given below:
main( ) {
/* p_fun3.c */ int i,fun1( ), fun2(), fun3(); int (*fp[3])(); /* Declaration of Pointer Array to a Function */ fp[0] = fun1; /* Assigning Address of Function to Pointer */ fp[1] = fun2; fp[2] = fun1; for( i=0 ; i <=2 ; i++) (*fp[i])(); /* Invoking Function through Pointer Array Fp*/
} fun1( ) { printf( \n In function One ); } fun2( ) { printf( \n In function Two ); } fun3( ) { printf( \n In function Three ); }
So from above program it is clear that we can call any number of functions with the help of Pointers, which is an advantage of using Pointers. Let us see following program in which a ROM-BIOS (Read Only Memory Basic Input Output system)Function used to Exit from DOS, which resides at memory location 0xFFFF0000:
#include dos.h
/* ExitFrom.c */
main( ) { void far (*p)( ); p = 0xFFFF0000; (*p)(); /* Invoking ROM BIOS Function through Pointer p */ }
Introduction of TSR
Introduction of TSR
Let us see following program in which a TSR changes characters on screen as given below: /* TSR1.c */ #include dos.h void interrupt our(); void interrupt (*prev)(); char far *scr = (char far *)0xB8000000L; main( ) { unsigned long int far *p; p = (char far *)36; /* Declaration of Pointer to Location 36 of IVT */ prev = *p; /* Save existing Address of ROM-BIOS Function to Pointer */ *p = our; /* Set up New Address */ keep(0,500); /* Make program resident in Memory */ }
/* TSR1
.c
Continued */
void interrupt our( ) { int i; for ( i = 0 ; i<= 3999 ; i = i + 2 ) { if ( *(scr + i) >= A && *(scr + i) <= Z ) *(scr + i) += 32; /* Change Uppercase to Lowercase */ if ( *(scr + i) >= a && *(scr + i) <= z ) *(scr + i) - = 32; /* Change Lowercase to Uppercase */ } (*prev)(); }
bytes long.
Keep() function is used to request DOS to allocate 500 * 16 Bytes to OUR program. It will make our Program Resident as this memory will never be given to any other program running under DOS. What happens actually when We hit a key from the keyboard Firstly, Interrupt Number 9 would be generated, then it is multiplied by 4 ( 9 * 4 = 36). Next the Address present in locations 36 to 39 would be picked and control would be passed to this address, Which is address of actual ROM-BIOS Service Routine. But here we do a little trick, We change this address at 36 to 39 locations. Now OUR function will be called which changes case of alphabets.
/* TSR2.c */ #include dos.h void interrupt our(); void interrupt (*prev)(); char far *kb = (char far *)0x417; main( ) { prev = getvect(9); /* To get address of Interrupt number 9 */ setvect(9,our); /* To set address of our function */ keep(0,500); /* Make program resident in Memory */ } void interrupt our() { (*prev)(); *kb = *kb | 64; }
How it Works ?
The Status of Caps Lock is stored in the sixth bit of byte at 0x417. Interrupt Number 9 is generated once when we hit a key and once when we release it. Now when any key is released, Our routine makes Caps Lock on.
7 Ins
2 Ctrl
1 Left Shift
0 Right Shift
#include dos.h void interrupt our(); void interrupt (*prev)(); char far *kb = (char far *)0x417; main( ) { prev = getvect(9); /* To get address of Interrupt number 9 */ setvect(9,our); /* To set address of our function */ keep(0,500); /* Make program resident in Memory */ } void interrupt our() { (*prev)();
(*prev)();
/* TSR2 .c */ The
Third TSR
Let us try to write a Time Bound TSR which Changes Color of Screen after a Fixed Time as given below: #include "dos.h /* TIMEB.C */ void interrupt our(); void interrupt (*prev)(); char far *scr = (char far *)0xB8000000L; int ticks; unsigned char color; main() { prev = getvect(8); setvect(8,our); keep(0,500); }
void interrupt our() /* TIMEB.C Contd. */ { int i; ticks++; if(ticks == 182) { for(i=1;i<=3999;i++) *(scr+i) = color; color++; ticks=0; } (*prev)(); }
#include "dos.h /* RAIN.C */ #include "stdlib.h" void interrupt our(); void interrupt (*prev)(); char far *scr = (char far *)0xB8000000L; int ticks; main() { prev = getvect(8); setvect(8,our); keep(0,1000); }
void interrupt our() { int i,col=1,row; char far *v,ch; while(1) /* Infinite loop */ { row = 1; ch = *(scr+row * 160 +col*2); for(;row<=24;row++) { v = scr + row*160+col*2; *(v-160)=' '; *v=ch; delay(100); } col++; } (*prev)(); }