HEADER FILES

Function prototypes for library functions supplied with the C compiler, and standard macros are declared in header files.

The ANSI standard on the C programming language lists the following header files;
Header file Description
assert.h Defines the assert debugging macro
ctype.h Character classification and conversion macros
errno.h Constant mnemonics for error codes
float.h Defines implementation specific macros for dealing with floating point mathematics
limits.h Defines implementation specific limits on type values
locale.h Country specific parameters
math.h Prototypes for mathematics functions
setjmp.h Defines typedef and functions for setjmp/longjmp
signal.h Constants and declarations for use by signal() and raise()
stdarg.h Macros for dealing with argument lists
stddef.h Common data types and macros
stdio.h Types and macros required for standard I/O
stdlib.h Prototypes of commonly used functions and miscellany
string.h String manipulation function prototypes
time.h Structures for time conversion routines

DEBUGGING

The ANSI standard on C includes a macro function for debugging called assert(). This expands to an if() statement, which if it returns true terminates the program and outputs to the standard error stream a message comprised of:

Assertion failed: <test>, file <module>, line <line number>

Abnormal program termination

For example, the following program accidentally assigns a zero value to a pointer!

#include <stdio.h>

#include <assert.h>

main()

{

/* Demonstration of assert */

int *ptr;

int x;

x = 0;

/* Whoops! error in this line! */

ptr = x;

assert(ptr != NULL);

}

When run, this program terminates with the message:

Assertion failed: ptr != 0, file TEST.C, line 16

Abnormal program termination

When a program is running okay, the assert() functions can be removed from the compiled program by simply adding the line;

#define NDEBUG

before the #include <assert.h> line. Effectively the assert functions are commented out in the preprocessed source before compilation, this means that the assert expressions are not evaluated, and thus cannot cause any side effects.

FLOAT ERRORS

Floating point numbers are decimal fractions, decimal fractions do not accurately equate to normal fractions as not every number will divide precisely by ten. This creates the potential for rounding errors in calculations that use floating point numbers. The following program illustrates one such example of rounding error problems;

#include <stdio.h>

void main()

{

float number;

for(number = 1; number > 0.4; number -= 0.01)

printf ("\n%f",number);

}

At about 0.47 (depending upon the host computer and compiler) the program starts to store an inaccurate value for 'number'.

This problem can be minimised by using longer floating point numbers, doubles or long doubles that have larger storage space allocated to them. For really accurate work though, you should use integers and only convert to a floating point number for display. You also should notice that most C compilers default floating point numbers to 'doubles' and when using 'float' types have to convert the double down to a float!

ERROR HANDLING

When a system error occurs within a program, for example when an attempt to open a file fails, it is helpful to the program's user to display a message reporting the failure. Equally it is useful to the program's developer to know why the error occurred, or at least as much about it as possible. To this end the ANSI standard on C describes a function, perror(), which has the prototype;

void perror(const char *s);

and is used to display an error message. The program's own prefixed error message is passed to perror() as the string parameter. This error message is displayed by perror() followed by the host's system error separated by a colon. The following example illustrates a use for perror();

#include <stdio.h>

void main()

{

FILE *fp;

char fname[] = "none.xyz";

fp = fopen(fname,"r");

if(!fp)

perror(fname);

return;

}

If the fopen() operation fails, a message similar to;

none.xyz: No such file or directory

is displayed.

You should note, perror() sends its output to the predefined stream 'stderr ', which is usually the host computer's display unit.

perror() finds its message from the host computer via the global variable 'errno' that is set by most, but not all system functions.

Unpleasant errors might justify the use of abort(). abort() is a function that terminates the running program with a message;

"Abnormal program termination"

and returns an exit code of 3 to the parent process or operating system.

Critical Error Handling With The IBM PC AND DOS

The IBM PC DOS operating system provides a user amendable critical error handling function. This function is usually discovered by attempting to write to a disk drive that does not have a disk in it, in which case the familiar;

Not ready error writing drive A

Abort Retry Ignore?

Message is displayed on the screen. Fine when it occurs from within a DOS program, not so fine from within your own program!

The following example program shows how to redirect the DOS critical error interrupt to your own function;

/* DOS critical error handler test */

#include <stdio.h>

#include <dos.h>

void interrupt new_int();

void interrupt (*old_int)();

char status;

main()

{

FILE *fp;

old_int = getvect(0x24);

/* Set critical error handler to my function */

setvect(0x24,new_int);

/* Generate an error by not having a disc in drive A */

fp = fopen("a:\\data.txt","w+");

/* Display error status returned */

printf ("\nStatus == %d",status);

}

void interrupt new_int()

{

/* set global error code */

status = _DI;

/* ignore error and return */

_AL = 0;

}

When the DOS critical error interrupt is called, a status message is passed in the low byte of the DI register. This message is one of;
Code Meaning
00 Write-protect error
01 Unknown unit
02 Drive not ready
03 Unknown command
04 Data error, bad CRC
05 Bad request structure length
06 Seek error
07 Unknown media type
08 Sector not found
09 Printer out of paper
0A Write error
0B ReadRead error
0C General failure

 

Your critical error interrupt handler can transfer this status message into a global variable, and then set the result message held in register AL to one of;
Code Action
00 Ignore error
01 Retry
02 Terminate program
03 Fail (Available with DOS 3.3 and above)


If you choose to set AL to 02, terminate program, you should ensure ALL files are closed first since DOS will terminate the program abruptly, leaving files open and memory allocated, not a pretty state to be in!

The example program shown returns an ignore status from the critical error interrupt, and leaves the checking of any errors to the program itself. So, in this example after the call to fopen() we could check the return value in fp, and if it reveals an error (NULL in this case) we could then check the global variable status and act accordingly, perhaps displaying a polite message to the user to put a disk in the floppy drive and ensure that the door is closed.

The following is a practical function for checking whether a specified disc drive can be accessed. It should be used with the earlier critical error handler and global variable 'status'.

int DISCOK(int drive)

{

/* Checks for whether a disc can be read */

/* Returns false (zero) on error */

/* Thus if(!DISCOK(drive)) */

/* error(); */

unsigned char buffer[25];

/* Assume okay */

status = 0;

/* If already logged to disc, return okay */

if ('A' + drive == diry[0])

return(1);

/* Attempt to read disc */

memset(buffer,0,20);

sprintf(buffer,"%c:$$$.$$$",'A'+drive);

_open(buffer,O_RDONLY);

/* Check critical error handler status */

if (status == 0)

return(1);

/* Disc cannot be read */

return(0);

}

  Casting, Interrupts, Pointers to Functions, and Prototyping.

 

 

Links:  Home C Programming Guide C++ programming Guide

Contact Me