Preprocessor Directives
The C pre-processor is a special program that runs before the C compiler. It processes every line that begins with a #, such as a #include statement. The pre-processor may add, remove, or change your code when handling the # statements.
#include
We’ve been using the #include statement since our first program in order to get access to C’s library functions (like printf in stdio.h). When the pre-processor sees a #include statement, it replaces the #include line with the contents of the included file. For example, when the pre-processor sees:
#include <stdio.h>then it replaces that line with the contents of the stdio.h file (which includes definitions for printf,
scanf, fprintf, etc.). Then, when the compiler sees a call to
printf, it knows what you mean because printf is defined in
your file.
Including a file like:
#include <stdio.h>tells the pre-processor to look for stdio.h in the standard
include directory (which is where all the library files live). If
instead you say:
#include "stdio.h"the pre-processor will first look for stdio.h in the current
directory. If it can’t find the file, it will hen look in the standard
include directory.
#define
The #define statement tells the pre-processor to find all
occurrences of one value in your code, and to replace them with
another value. This can be used in two ways: to define constants
and to define macros (simplified functions).
Constants
A constant in C is defined like this:
#define name valueHere, name is the name we are giving the constant, and value is
the value we would like it to have. Here is an example:
#define PI 3.14159Now, we can use PI in our code when we want the value
3.14159. For example:
int radius = 10;
double area = PI * radius * radius;When the pre-processor sees a #define constant, it replaces all
occurrences of the constant’s name with it’s specified value. So
by the time the pre-processor gets done with it, the above code
looks like:
int radius = 10;
double area = 3.14159 * radius * radius;Macros
A macro is simplified function that includes a name and a list of
arguments. They are defined using the #define statement, just
like constants. For example:
#define SUM(a, b) a+bWhen the preprocessor sees a call to the macro, it will replace the macro call with the macro formula. For example, if we do:
int x = 3;
int y = 4;
int result = SUM(x, y);Then the pre-processor will change the last line to be:
//Uses x as a and y as b in the macro formula
int result = x + y;
Just like other pre-processor directives, the compiler never sees the macro itself. It only sees the final result, after the pre-processor has replaced the macro call with the macro formula.
As another example, let’s try to write a macro that computes the difference of two squares:
//This is not right!
#define DIFF_SQUARE(a, b) a*a – b*b This macro may look right (and this is how we would write a diffSquare function), but it has some problems. For example:
int x = 4;
int y = 3;
int c = 2;
int d = 1;
int result = DIFF_SQUARE(x-c, y-d);The pre-processor will replace the call to DIFF_SQUARE with the
macro value. It will use x-c as the value for a, and y-d as
the value for b. Here’s what the last line will become:
int result = x-c*x-c – y-d*y-d;However, what we WANT is:
int result = (x-c)*(x-c) – (y-d)*(y-d);To get this substitution, we need to add parentheses to the original macro:
#define DIFF_SQUARE(a, b) (a)*(a) – (b)*(b)Here is a macro that returns the minimum of two numbers:
#define MIN(a, b) a < b ? a : bThis uses the ternary conditional operator. It means: if a is less
then b, then a is the minimum. Otherwise, b is the minimum.
Here is a macro that eats all input left in the input buffer. This can be VERY useful as any unexpected input will stay in the input buffer. It reads one character at a time until it runs out of input.
#define FLUSH() while (getchar() != '\n')#ifdef, #ifndef
There is also a pre-processor if-statement that checks to see whether or not a constant has been defined. Here’s the format:
#ifdef (pre-processor constant)
code
#endifThe code inside this #ifdef/#endif block will only be
compiled if the pre-processor constant was defined. For example:
#define SIZE 10
//(elsewhere)
#ifdef SIZE
int nums[SIZE];
#endifIn this example, we only include the int nums[SIZE]; line
in our program if the SIZE constant has already been defined.
There is a similar construct called #ifndef, which evaluates to
true if a constant has NOT been defined. For example:
#ifndef SIZE
printf("Define SIZE!\n");
#endifThe printf statement will only be part of the program if the
SIZE constant has not been defined. The #ifndef statement
will be very useful when we start to break our programs into
several files – it will help ensure that we don’t end up including the
same information twice when we link our files together.