Previous: 3.3.2 Macros
Up: 3.3 Coding Programs for Readability
Next: 3.3.4 Conditional Compilation
Previous Page: 3.3.2 Macros
Next Page: 3.3.4 Conditional Compilation

3.3.3 Including Header Files

The second feature provided by the preprocessor allows us to break our source files into smaller pieces to be reassembled at compile time. Using functions to hide details of algorithms and macros to hide the syntax and ``magic numbers'' to make our programs more readable often results in many function prototype statements and macro definitions at the beginning of source code files. These may also be hidden in separate files, and included in the source file by the preprocessor. The files containing this information to be included are called include files or header files, and by convention, are named with a .h extension on the file name. Header files are also often used to provide common macro definitions and prototype statements that may be useful in may programs (or as we shall see later, in many files making up a single program). An example of the later case are the standard library functions provided in C; the prototype statements for these functions should be available to any program which chooses to use the functions. In many of our programs so far, we have used the library functions printf() and scanf(). Where are the prototypes for these? As well as providing the code for library functions, all standard C implementations provide a set of .h files with this information. The file stdio.h contains the prototypes and macros needed to use the I/O library. (We have not needed this file before because the compiler will make assumptions about functions if prototypes are not provided. Sometimes these assumptions are ``safe'', but often they are not. It is a good idea, from now on, to include stdio.h in any program using the I/O library).

The statements and directives in an include file are inserted in a source file when the preprocessor encounters an #include directive in the original source file. To include stdio.h the directive is:

#include <stdio.h>
The angle brackets, < and >, surrounding the filename indicate to the preprocessor that the file, stdio.h, is to be found in ``the usual place'' where standard header files are kept on the system (this is system dependent), and its contents placed in the source code in place of the #include directive. Any other directives within the included file (such as #define or other #include directives) are also processed at this time.

Besides the standard header files, as a programmer you can create and include your own header files for your programs. For example, in our niceday.c program, we defined macros for TRUE and FALSE. These macros are very common in many programs, so it would be convenient if we could enter those definitions in a single header file and simply include that header file in any program the uses those macros. This header file might be called tfdef.h and contain:

/*   File: tfdef.h
     Programmer: Programmer Name
     This file contains the definitions of TRUE and FALSE
*/

#define TRUE 1 #define FALSE 0

To include these definitions in a .c source file, use the directive:
#include "tfdef.h"
Notice in this instance that the file name is surrounded by double quote, ", characters rather than the angle brackets used before. This syntax tells the preprocessor that the header file is to be found in the same directory as the .c source file currently being processed.

Again, in our nice day program, all of the other macro definitions and prototypes relating just to this program may also be placed in a header file, say niceday.h:

/*   File: niceday.h
     Programmer: Programmer Name
     This file contains the definitions of macros and prototypes
     for functions used by the niceday program.
*/

#define TOO_COLD 80 #define TOO_HOT 90

#define HOT_DAY(t) ((t) > TOO_HOT) #define COLD_DAY(t) ((t) < TOO_COLD)

#define ANY_DAYS(n,b) (((n) + (b)) > 0)

int nice_day(int temp); int print_results(int nice, int bad, int temp_sum);

and replaced in niceday.c with:
#include "niceday.h"
Thus, the beginning of niceday.c has been reduced to:
/*   File: niceday.c
     Programmer: Programmer Name
     Date: Current Date
     This program counts the number of nice days in a set of high
     temperature data.
*/

#include <stdio.h> #include "tfdef.h" #include "niceday.h"

main() { ...

Notice we include stdio.h at the head of the source file. Its contents are available for use by the entire source file. We also declare the function prototypes for nice_day() and print_results() in the file niceday.h outside main(). A declaration outside a function is called an external declaration. The scope of an external declaration is the entire file from the point of the declaration; i.e. all code that follows the external declaration can use the declared item. Since stdio.h is included outside main(), the declarations for scanf() and printf() are also external. External declaration of functions is convenient since it avoids repeated declarations of the same function. On the other hand, external declarations of variables leads to poorly structured programs and destroys modularity of functions. External declarations of variables is strongly discouraged.

In summary, the syntax of the #include directive is:

with the semantics that the contents of the file, filename, is to be inserted in the source file in place of the #include directive. (Note: here the angle brackets are part of the syntax of the directive). Other directives in the included file are also processed. In the first form of the directive, the header file is searched for in the ``usual place'' for system header files, and in the second case, it is to be found in the current directory. The advantages of using the #include directive are twofold:
  1. Information such as macro definitions and prototype statements that are useful in multiple program files need only be entered in a single place and then included where needed. This also facilitates changes; the change need be made only in a single place.
  2. Details of macro definitions and prototypes are hidden from the view of the reader, thus alleviating clutter and information overload and allowing a reader of the program to concentrate on the logic of the code itself.



Previous: 3.3.2 Macros
Up: 3.3 Coding Programs for Readability
Next: 3.3.4 Conditional Compilation
Previous Page: 3.3.2 Macros
Next Page: 3.3.4 Conditional Compilation

tep@wiliki.eng.hawaii.edu
Wed Aug 17 08:21:42 HST 1994