Last updated: July 1, 2021
 
red bullet point Home
red bullet point Grant
red bullet point Objective
red bullet point Strategy
red bullet point Timeline
red bullet point Project Team
red bullet point Technician
red bullet point Hardware
red bullet point Software
red bullet point Account
red bullet point Teaching Material
red bullet point Course / Lab
red bullet point Research
red bullet point Resource
red bullet point FAQ
red bullet point Vacancy
 
arrow HPCCC Website
 
Total Visitors since
28 Aug 2003: 424791
 
Valid XHTML 1.0!
 
Valid CSS!
Click here to download the PDF version

Chapter 13: The Preprocessor
============================
* Preprocessing occurs before a program is compiled.
* Possible actions:
1. inclusion of other files
2. definition of symbolic constants and macros
3. definition of conditional compilation
4. conditional execution of preprocessor directives
* All preprocessor directives begin with "#"

The "#include" Preprocessor Directive
-------------------------------------
* The "#include" directive causes a copy of a specified file to be
included in place of the directive.
* Two forms:
1. #include <filename> : the preprocessor searches through
predesignated directories, in an implementation-dependent
manner, e.g., standard library header files.
2. #include "filename" : the preprocessor searches in the same
directory as the file being compiled for the file to be
included, e.g. programmer-defined header files.

* The "#include" directive is used with programs consisting of several
source files that are to be compiled together.
* A header file containing declarations common to the separate files.

The "#define" Preprocessor Directive: Symbolic Constants
--------------------------------------------------------
* The "#define" directive creates symbolic constants - constants
represented as symbols, and macros - operations defined as symbols.
* The format:
#define identifier replacement-text
* When this line appears in a file, all subsequent occurences of
"identifier" will be replaced by "replacement-text" automatically
before the program is compiled.
* E.g.
#define PI 3.14159

* Symbolic constants enable the programmer to create a name for a
constant and use the name throughout the program.
* If the constant needs to be modified throughout the program, it can
be modified once in the "#define" directive
* When the program is recompiled, all occurrence of the constant in
the program will be modified automatically.

The "#define" Preprocessor Directive: Macros
--------------------------------------------
* A macro is an operation defined in a "#define" preprocessor
directive.
* As with symbolic constants, the macro-identifier is replaced in the
program with the replacement-text before the program is compiled.
* Macro may be defined with or without arguments.
* A macro without arguments is processed like a symbolic constant.
* In a macro with arguments, the arguments are substituted in the
replacement text, then the macro is expanded.
* E.g.
#define CIRCLE_AREA(x) ( PI * (x) * (x) )
....
area = CIRCLE_AREA(4);
is expanded to (before compile time),
area = ( 3.14159 * (4) * (4) );
* The parentheses around each "x" in the replacement text force the
proper order of evaluation when the macro argument is an expression.
* E.g.
area = CIRCLE_AREA(c+2);
is expanded to
area = ( 3.14159 * (c+2) * (c+2) );

* Macro "CIRCLE_AREA" could be defined as a function.
* E.g.
double circleArea(double x)
{
return 3.14159 * x * x;
}
* But the overhead is associated with the function.
* A disadvantage of macro is that its argument is evaluated twice.

* If the replacement text for a macro or symbolic constant is longer
than the remainder of the line, a bachslash (\) must be placed at the
end of the line.

* Symbolic constants and macros can be discarded using the "#undef"
preprocessor directive.
* Once undefined, a name can be redefined with "#define".

Conditional Compilation
-----------------------
* Conditional compilation enables the programmer to control the
execution of preprocessor directives, and the compilation of program
code.
* Each of the conditional preprocessor directives evaluates a constant
integer expression.
* E.g.
#if !defined(NULL)
#define NULL 0
#endif
* If NULL is not defined, it is defined by "#define NULL 0"
* If it is defined, the "#define" directive is skipped.
* Every "#if" ends with "#endif".

* Directives "#ifdef name" and "#ifndef name" are shorthand for "#if
define(name)" and "#if !defined(name)" respectively.
* A multiple-part conditional preprocessor may be tested using the
"#elif" and the "#else" directives.

* To comment out a large portions of code with comment,
#if 0
code prevented from compiling
#endif

* To insert some debugging statement, you may
#ifdef DEBUG
printf("Variable x = %d\n", x);
#endif

The "#error" and "#pragma" Preprocessor Directives
--------------------------------------------------
* The "#error" directive
#error tokens
prints an implementation-dependent message including the token
specified in the directive.

* The "#pragma" directive
#pragma tokens
cause an implementation-defined action.

Predefined Symbolic Constants
-----------------------------
* There are five predefined symbolic constant.
__LINE__ The line number of the current source code line.
__FILE__ The presumed name of the source file.
__DATE__ The date the source file is compiled
__TIME__ The time the source file is compiled
__STDC__ The indicator of ANSI compliant if it is 1.

Assertions
----------
* The "assert" macro - defined in the "assert.h" header file - tests
the value of an expression.
* The the value of expression is 0, then "assert" prints an error
message and calls function "abort" (of "stdlib.h") to terminate
program execution.
* E.g.
assert(x <= 10);
* If "x" is greater than 10, an error message containing the line
number and file name is printed, and the program terminates.
* When assertions are no longer needed, the line
#define NDEBUG
is inserted in the program file rather than deleting each assertion
manually.









©2002-2024 Hong Kong Baptist University. All Rights Reserved.