Preprocessor directives offer a lot of advantages and flexibility to a C programmer. Before diving into
specific instances of preprocessor directives, we would benefit from understanding what a preprocessor is.
A preprocessor is a program that processes our written code before compilation. During this process,
preprocessor will explicitly look for preprocessor directives and follow their instructions. At the time of
compilation, the preprocessor will have modified the code in the program accordingly to the found
directives.
Some of the most relevant preprocessor directives are:
Defining symbols, that is #define and #undef are instructions that are dealt with by the preprocessor.
A good way to identify these or any other preprocessor directives, for that matter, is the # symbol at the beginning of the instruction and a lack of ; at the end.
The preprocessor directive #define, as
the name suggests, allows us to define constant values and expressions.
Example of #define in C code:
#include<stdio.h>
#defineCONSTANT1
intmain(void)
{
if(CONSTANT==1)
printf("CONSTANTisdefined");//program prints this line
else
printf("CONSTANTisnotdefined");
return0;
}
In the C code example above, we are defining a constant. This constant, thus
cannot be modified during the
runtime of the program. However, it is accessible during runtime because the preprocessor replaced the
constant name CONSTANT everywhere in our program with the
assigned value of 1
The #define can define expressions,
too. Expressions, in turn, can take varying programs. To better
understand this consider the code example below for a moment:
#include<stdio.h>
#definePRODUCT(a,b) ((a) * (b))
intmain(void)
{
printf( "%d", PRODUCT(10, 5) );//prints 50
return0;
}
The preprocessor directive #undef has
opposing functionality to the discussed #define directive.
Since #undef undefines or removes constant values and
expressions that were defined by the #define.
#undef PRODUCT
#undef CONSTANT
2. Content inclusion: #include
The #include directive is used in most C programs because it
marks the place in the program where this directive needs to be replaced with the contents of the
specified filename. Let's say our program contains this line of code #include <stdio.h>. The preprocessor will run before
compilation of the program, it will notice this line of code and replace it with all the data that is
inside the <stdio.h> library. This allows the program to
access all the functions in the runtime that this library contains.
Filename or library name can be specified inside angle brackets ( < > ) or inside double quotes.
In the former case (#include <stdio.h>), the proprocessor
expects and checks for this file inside the standard library. In the latter case (#include "our_header.h"), the preprocessor will firstly check for
this file at user defined locations and will only check inside the standard library whenever user
defined locations do not contain the specified file.
3. Conditional compilation: #ifndef,
#ifdef and #endif
Both #ifdef and #ifndef directives are typically used for different purposes, yet
both need to be closed with an #endif directive. The #ifndef directive is commonly used as a header guard. You
can check this in the C code example below:
#ifndefHEADER
#defineHEADER
intfunctional_definition(void);
#endif
Here we are checking if HEADER is not defined. On such an
occassion #ifndef returns true. Which makes the lines of C code wrapped inside the #ifndef and #endif
directives compilable.
Notice the #define HEADER (On line 2). This previously
discussed
directive will define HEADER constant. The next time this header file gets called, HEADER will be
defined and the #ifndef HEADER will return false. Which will
prevent the same information being compiled again. Our header is now guarded, all thanks to #ifndef and #endif
preprocessor directives.
With the #ifdef the whole idea is rather similar to that of
#ifndef. The difference is that the former returns true if the
constant is, in fact, defined and false if it is not. This is useful for multi device applications
because it allows to enable certain parts of the code depending on the device that runs the program.
4. File instruction: #pragma
The #pragma preprocessor directive is useful in large programs.
This directive has the effect on the compiler's behaviour by specifying instructions to certain
operating
system. A widely supported instruction across many systems is once.
Including #pragma once at the top of your header file provides
a guard from multiple compilations. You have already seen how to achieve this result in the Conditional compilation: #ifndef,
#ifdef and the #endif section above. Note that you do not
need to use both directive methods for the same purpose.
5. Quiz of reader's knowledge
Quiz : Preprocessor Directives in C
1For
what purpose is #pragma once used?
2Which preprocessor directive returns true when the constant is not
defined?
3If
the value of #include is written in double quotes, as in #define "stdio.h",