Tip:
Highlight text to annotate it
X
The preprocessor is a program invoked by the compiler that modifies the source code before
the actual compilation takes place. This modification is done according to the preprocessor directives
that we include in our source files. The directives are easily distinguished from normal programming
code in that they all start with a hash sign (#). They must always appear as the first
non-whitespace character on a line.
The first directive we’ll look at is #include, which inserts the contents of a specific file
into the current one. If the filename is enclosed between angle-brackets () the compiler will
search for the file in the default directory where it is configured to look for the standard
header files. If we instead specify the filename between double-quotes the compiler will first
search for the file in the same directory as the source file and in case it is not there
it will then search among the standard header files. We can also use the double quotes to
specify an absolute or relative path to the file that we want to include.
Another important directive is #define, which is used to define macros. We first specify
the name of the macro, followed by what we want it to be replaced by. The preprocessor
will then go through and change any occurrences of the macro with whatever comes after the
it in its definition until the end of the line. By convention, the macro should be named
in uppercase with each word separated by an underscore. That way they are easy to spot
when reading the source code.
A #define directive shouldn’t be used to override a previously defined macro directly.
Doing so will give a compiler warning. In order to change a macro we need to first undefine
it, using the #undef directive, before we redefine it. Note that we do not get a warning
for attempting to undefine a macro that is not currently defined.
A macro can if we want to be made to take arguments. This allows us to create compile-time
functions. For example, we here have a macro function that evaluates to the maximum of
two values. To use it we just need to call it as if it was a normal C++ function. Keep
in mind that for this kind of function to work we may only use arguments that are known
at compile time.
If we want to break a macro function across several lines we can do so by using the backslash
symbol (\). This will escape the newline character that marks the end of a preprocessor directive.
As a final note I want to point out that although #define directives can be powerful they also
tend to make the code more difficult to read and debug. #define should therefore only be
used where it is absolutely necessary. C++ code such as constant variables, enums, and
inline functions can often accomplish the same goal more efficiently and safely than
#define directives can.