I don’t touch upon preprocessor directives in deep detail in the book. The #include
and #define
directives are mentioned, but they’re only two of many preprocessor directives available in the C Language.
What’s a Preprocessor Directive?
A preprocessor directive is given to the compiler before the C code is compiled. The compiler works through the preprocessor directives first, making substitutions, inclusions, and even decisions before the source code is translated into object code.
Here are the various preprocessor directives:
#include
#define
#undef
#if
#endif
#elif
#else
#ifndef
The place you’ll see most of these directives used are in the various header files. In fact, I recommend you peruse the header files to explore the possibilities of how these directives are put to work. That’s because most of your code probably won’t use these guys.
#include
The #include
directive brings in code from another file, typically a header file. The directive is followed by a filename. When the filename is enclosed in angle brackets:
#include
the compiler looks for that file in the /usr/include
(or similar) directory. Otherwise, when the filename is enclosed in double quotes:
#include "project.h"
the file is looked for in the current directory.
#define
In the book, I describe how #define
is used to create constants and make substitutions. It’s official definition is “macro substitution.” It creates shortcuts. When the compiler encounters this preprocessor directive, it works through the code and makes substations as necessary. For example:
#define ROWS 5
Above, the compiler would search for any instance of ROWS
and replace it with the value 5.
You can include variables in the macro expansions, which is done for the definition of putchar()
in the stdio.h header file
#define putchar(x) putc(x,stdout)
Be careful when making such expansions, however, as sometimes the compiler may expand the macro twice.
#undef
The #undef
preprocessor directive un-defines something previously created by the #define
directive. This is an example of a directive you’ll often find in a header file, but not necessarily in your code.
#if
#endif
The #if
directive evaluates a condition. When the condition is true, the statements that follow #if
are executed, up until the #endif
directive. I’ve actually used this directive in my code a long, long time ago. I created a constant to determine whether the computer was capable of displaying color text or not:
#define COLOR 1
Later #if
directives examined that constant to determine whether color information was compiled into the code or not:
#if COLOR
/* color code goes here */
#endif
Of course, I had to manually set the COLOR
value. That was okay; it allowed me to use one source code file to generate two different versions of the program, one for color systems and one for monochrome.
Remember that the #endif
directive is required to terminate a block of #if
statements.
#elif
#else
These two directives correspond to else if
and else
items in an C language if decision tree. They allow you to construct complex decisions using preprocessor directives.
#ifdef
#ifndef
These directives form specific if conditions based on whether something is defined or not yet defined. The value of what’s defined doesn’t matter, just whether the item has been defined or not. For example:
#ifndef BLORFUS
#define BLORFUS 64
#endif /* BLORFUS */
The above example creates the constant BLORFUS
if it hasn’t yet been defined. You’ll see lots of those examples inside the header files, if you choose to peruse them. Read my February 21 2015 Lesson for a specific example of how to use these directives.