Previous | Table of Contents | Next

### A Reminder about Prototypes

The code in this book works on both Unix K&R and the more modern MS-DOS compilers. This affects the code in this book mainly in the area of function parameters in both prototypes and the function body itself. For the function body, all code in this book will use old-fashioned parameter specifications like this:

    int main( argc, argv )
    int argc;
    char *argv[];
    {

    ...

This is the only method of parameter declaration acceptable to K&R compilers, and as such it has the blessing of the ANSI standard. A few compilers (Microsoft C 6.0 at Warning Level 4, for example) will issue a warning when it encounters this type of function declaration, so be prepared to ignore those warnings. Declaring function parameters in this method will generally have no effect on code reliability or readability, so using the K&R style should be considered a benign anachronism.

Parameters in function declarations present a little more of a problem. The ANSI C specification will accept old style K&R function declarations (such as int main();), but there are good reasons to specify all function arguments in the declaration. When using full prototyping—as in int main( int argc, char *argv[] );—the compiler checks for correct parameter passing when it encounters a call to a function. This helps avoid one of the most commonplace C coding mistakes; incorrect parameter types.

To use this prototyping, and at the same time to stay compatible with K&R compilers, all function prototypes are given in two forms: a K&R-compatible prototype and a full ANSI C prototype. The ANSI C prototypes are selected through a check for __STDC__, a predefined macro defined when a compiler conforms to the ANSI C standard. So the prototype for a set of functions in a header file will look something like this:

    #ifdef __STDC__

    int main( int argc, char *argv[] );
    FOO *open_foo( char *name );

    #else /* __STDC__ */

    int main();
    FOO *open_foo();

    #endif /* __STDC__ */

This compromise approach definitely hurts readability, and it is probably not the way to go during code development. But once a set of routines is working properly and not likely to be changed, this type of header file will work fine.

ANSI C compiler users will find that a problem with this header file crops up with numerous MS-DOS compilers. Compilers such as Microsoft C or Borland C++ are ANSI C compilers, but by default they include a number of language extensions, such as far pointers, alternate calling conventions, and so on. When these language extensions are enabled (as they are by default), __STDC__ is not defined, since the compiler is not operating strictly as an ANSI C compiler. This means that the correct function prototypes will not be invoked.

The solution to this problem is to compile the code in this book with the compiler in ANSI C mode. Put the compiler in this mode generally by disabling extensions. Microsoft C accomplishes this from the command line with the /Za switch. Borland C++ uses the -A switch to disable C extensions.

To adapt this code for a specific use on a specific compiler, you may want to eliminate the “#ifdef __STDC__” lines in the header file and code. As more and more compilers use ANSI C prototypes and parameter definitions, this portability machinery will become less and less useful.

### MAIN-C.C AND MAIN-E.C

Another piece of utility code used throughout this book is the “main()” program for the compression and expansion programs. Any piece of compression code needs to be plugged into a main program that accepts command-line arguments, opens files, calls the compression routines, then closes the files. For simplicity, I have created two versions of this code: one for the compression program (MAIN-C.C) and one for the expansion program (MAIN-E.C).

Both MAIN-C.C and MAIN-E.C expect to find a compression or expansion routine in another file, a help routine to explain command-line parameters, and an external string with the name of the compression technique being used. The declarations for the functions and name are found in MAIN.H. MAIN.H should be included in the compression module to ensure that the routines are properly typed. MAIN.H is shown next.

The idea behind these two routines is that the infrastructure of a compression test program should not have to be rewritten every time a new compression module is coded. A new routine should just have to interface with the existing compression code.

    /********************** Start of MAIN.H ***********************/

    #ifndef _MAIN_H
    #define _MAIN_H

    #ifdef _STDC_
    void CompressFile( FILE *input, BIT_FILE *output, int argc, char *argv[] );
    void ExpandFile( BIT_FILE *input, FILE *output, int argc, char *argv[] );

    #else /* __STDC__ */

    void CompressFile();
    void ExpandFile();

    #endif /* __STDC__ */

    extern char *Usage;
    extern char *CompressionName;
    #endif /* _MAIN_H */

    /************************* End of MAIN.H ************************/

Previous | Table of Contents | Next