Introduction and Motivation
- The first step in compiling any C program is the preprocessor,
a sort of automated editor that modifies ( a copy of ) the source code
before passing it on to the compiler to translate into machine language
code.
- One of the tasks of the preprocessor is to strip off all comments, which the compiler ignores.
- The preprocessor also responds to directives
in the code, which give the preprocessor explicit instructions on how
to edit the source code before passing it on to the compiler.
The #include Preprocessor Directive
- The #include directive causes the preprocessor to read in the
contents of some other file, which may in turn #include some other
file(s), etc.
- See notes on "Writing Large Programs" for full details, including typical contents of #included files and how to avoid circular includes.
The #define Preprocessor Directive
- The #define directive is used to "define" preprocessor
"variables", which can then be used in one of three ways, as shown in
the following three sections.
- It is also possible to define preprocessor variables when invoking
the compiler, either as command-line arguments or through the IDE.
Using #define For Boolean Testing
- Sometimes the preprocessor only needs to know whether a particular preprocessor variable is defined or undefined.
- In this case, use #define and #undef to turn such variables "on" or "off"
- The status of a preprocessor variable can be tested with #ifdef or
#ifndef, either of which starts a block of code that must be terminated
by a matching #endif. ( #elif and #else can also be used, if you need
more complicated if-else type blocks. )
- For example, you may have a number of printing statements that you
only want active when debugging. You can "protect" them in a "ifdef"
block as follows:
#ifdef DEBUG
printf( "Now beginning loop %d with x = %f, y = %f, and z = %f\n", i, x, y, z );
#endif
Then you can turn all such blocks on or off at once using
#define DEBUG
or
#undef DEBUG
Boolean type preprocessor variables can be defined from the UNIX command-line using the "-D" flag to gcc, i.e. "-DDEBUG".
Using #define For Text Substitution
- The most common use for #define is for automatic substitution of a text string.
- This was covered in detail, including common pitfalls in the Defined Constants section of Writing Large Programs
Using #define To Define Macros
- In addition to simple variable substitutions, it is also possible to create pre-processor macros that take arguments.
- Macros operate much like functions, but because they are
expanded in place they are generally faster, since they do not invoke
the overhead of transferring control over to a function and then
transferring control back again.
- However there are some potential dangers when using macros instead of functions, as described below.
- Example:
#define PI 3.14159
#define SQUARE(x) x * x
...
area = PI * SQUARE( radius );
which will be seen by the compiler as:
area = 3.14159 * radius * radius;
Note: It is very important to include parentheses around all
variables used in a preprocessor macro, as well as around the entire
definition.
Exercise: What will be the effects of the following? Which is correct?:
-
#define SQUARE(x) x * x
...
abSquared = SQUARE( a + b );
-
#define SQUARE(x) (x) * (x)
...
a_over_b_squared = a / SQUARE( b );
-
#define SQUARE(x) ( (x) * (x) )
...
answer = SQUARE( a + b ) / SQUARE( b );
Landmine! Do not use auto-increment or
decrement operators, assignment statements, or function calls in
combination with preprocessor macros. Consider:
for( i = 0; i < 10; )
printf( "%d squared = %d\n, i, SQUARE( i++ ) );
Preprocessor macros can take multiple arguments:
#define A_MOD_B(a,b) ( (a) % (b) )
Preprocessor macros can also make use of previously defined macros
#define MAX(a,b) ( (a) > (b) ? (a) : (b) )
#define MAX3(a,b,c) ( ((a) > (b)) ? MAX((a),(c)) : MAX((b),(c)) )
// or #define MAX3(a,b,c) ( MAX((a), MAX((b),(c)) )
Preprocessor macros can span multiple lines only if the end of line is explicitly escaped:
#define MIN(a,b) ( (a) < (b) ? \
(a) : \
(b) )
- Note that macros do not check the types of their arguments, which can have both good and bad consequences.
Predefined Macros
- There are a number of macros automatically pre-defined by the
compiler, inlcuding the following list. Note that each one begins and
ends with TWO underscore characters:
- __LINE__ - The line number of the current file being compiled
- __FILE__ - The name of the current file being compiled
- __DATE__ - The current date
- __TIME__ - The current time
The #pragma Preprocessor Directive
- The #pragma directive is used to give the preprocessor ( and
compiler ) specific details on exactly how to compile the program. For
example, specific compiler warnings can be ignored, or warning levels
changed up or down for different sections of code.
- Examples:
- #pragma page( ) // Forces a form feed in the listing
- #pragma warning( disable: 2044 ) // Disables warning number 2044
- #pragma line 100 // Sets the current line number to 100 for listing and reporting purposes.
No comments:
Post a Comment