Pre Processor Directives
Pre Processor Directives
The preprocessor is a program that is invoked by the compiler to process code before
compilation. Commands for that program, known as directives, are lines of the source
file beginning with the character #, which distinguishes them from lines of source
program text. The effect of each preprocessor directive is a change to the text of the
source code, and the result is a new source code file, which does not contain the
directives. The preprocessed source code, an intermediate file, must be a valid C or
C++ program, because it becomes the input to the compiler.
The syntax of preprocessor directives is independent of, but similar to, the syntax of
the rest of the language, and the lexical conventions of the preprocessor differ from
those of the compiler. The preprocessor recognizes the normal C and C++ tokens, as
well as other characters that enable the preprocessor to recognize file names, the
presence and absence of white space, and the location of end-of-line markers.
Preprocessor directives and the related subject of macro expansion are discussed in
this section. After an overview of preprocessor directives, the topics covered include
textual macros, file inclusion, ISO standard and predefined macro names, conditional
compilation directives, and pragmas.
Preprocessor Overview
Preprocessing is a preliminary operation on C and C++ files before they are passed to
the compiler. It allows you to do the following:
A token is a series of characters delimited by white space. The only white space
allowed on a preprocessor directive is the space, horizontal tab, vertical tab, form
feed, and comments. The new-line character can also separate preprocessor tokens.
#define
Defines a macro.
#undef
Removes a preprocessor macro definition.
#error
Defines text for a compile-time error message.
#include
Inserts text from another source file.
#if
Conditionally suppresses portions of source code, depending on the result of a
constant expression.
#ifdef
Conditionally includes source text if a macro name is defined.
#ifndef
Conditionally includes source text if a macro name is not defined.
#else
Conditionally includes source text if the previous #if, #ifdef, #ifndef, or #elif
test fails.
#elif
Conditionally includes source text if the previous #if, #ifdef, #ifndef, or #elif
test fails, depending on the value of a constant expression.
#endif
Ends conditional text.
#line
Supplies a line number for compiler messages.
#pragma
Specifies implementation-defined instructions to the compiler.
A preprocessor directive ends at the new-line character unless the last character of the
line is the \ (backslash) character. If the \ character appears as the last character in the
preprocessor line, the preprocessor interprets the \ and the new-line character as a
continuation marker. The preprocessor deletes the \ (and the following new-line
character) and splices the physical source lines into continuous logical lines. White
space is allowed between backslash and the end of line character or the physical end
of record. However,this white space is usually not visible during editing.
Except for some #pragma directives, preprocessor directives can appear anywhere in
a program.
>>-#--define--identifier--+--------------------------+---------->
| .-,--------------. |
| V | |
'-(----+------------+-+--)-'
'-identifier-'
.----------------.
V |
>----+------------+-+------------------------------------------><
+-identifier-+
'-character--'
• The #define directive can be used to create a name for a numerical, character,
or string constant, whereas a const object of any type can be declared.
• A const object is subject to the scoping rules for variables, whereas a constant
created using #define is not.
• Unlike a const object, the value of a macro does not appear in the
intermediate source code used by the compiler because they are expanded
inline. The inline expansion makes the macro value unavailable to the
debugger.
• A macro can be used in a constant expression, such as an array bound,
whereas a const object cannot.
• The compiler does not type-check a macro, including macro
arguments.
Object-Like Macros
If the statement
int arry[COUNT];
appears after this definition and in the same file as the definition, the preprocessor
would change the statement to
int arry[1000];
#define a 10
a.2
Identifiers that are partially built from a macro expansion may not be produced.
Therefore, the following example contains two identifiers and results in a syntax
error:
#define d efg
abcd
Function-Like Macros
More complex than object-like macros, a function-like macro definition declares the
names of formal parameters within parentheses, separated by commas. An empty
formal parameter list is legal: such a macro can be used to simulate a function that
takes no arguments. C adds support for function-like macros with a variable number
of arguments.
C++ supports function-like macros with a variable number of arguments, as a
language extension for compatibility with C.
For portability, you should not have more than 31 parameters for a macro. The
parameter list may end with an ellipsis (...). In this case, the identifier
__VA_ARGS__ may appear in the replacement list.
#define SUM(a,b,c) a + b + c
SUM(1,,3) /* No error message.
1 is substituted for a, 3 is substituted for c.
*/
This language feature is an orthogonal extension of C++.
If the identifier list does not end with an ellipsis, the number of arguments in a macro
invocation must be the same as the number of parameters in the corresponding macro
definition. During parameter substitution, any arguments remaining after all specified
arguments have been substituted (including any separating commas) are combined
into one argument called the variable argument. The variable argument will replace
any occurrence of the identifier __VA_ARGS__ in the replacement list. The following
example illustrates this:
Commas in the macro invocation argument list do not act as argument separators
when they are:
• In character constants
• In string literals
• Surrounded by parentheses
The following line defines the macro SUM as having two parameters a and b and the
replacement tokens (a + b):
#define SUM(a,b) (a + b)
This definition would cause the preprocessor to change the following statements (if
the statements appear after the previous definition):
c = SUM(x,y);
c = d * SUM(x,y);
c = (x + y);
c = d * (x + y);
Use parentheses to ensure correct evaluation of replacement text. For example, the
definition:
y = SQR(a + b);
y = ((a + b) * (a + b));
Without parentheses in the definition, the correct order of evaluation is not preserved,
and the preprocessor output is:
y = (a + b * a + b);
expands
x(20,10)
to
x(20+1,10+1) + 4
rather than trying to expand the macro x over and over within itself. After the macro x
is expanded, it is a call to function x().
#define debug
You can change the definition of a defined identifier or macro with a second
preprocessor #define directive only if the second preprocessor #define directive is
preceded by a preprocessor #undef directive. The #undef directive nullifies the first
definition so that the same identifier can be used in a redefinition.
Within the text of the program, the preprocessor does not scan character constants or
string constants for macro invocations.
The following program contains two macro definitions and a macro invocation that
refers to both of the defined macros:
/**
** This example illustrates #define directives.
**/
#include <stdio.h>
int main(void)
{
int x = 2;
int y = 3;
PRNT(SQR(x),y);
return(0);
}
#include <stdio.h>
int main(void)
{
int x = 2;
int y = 3;
return(0);
}
value 1 = 4
value 2 = 3
The most common use of the macro replacement is in defining a constant. In C++
you can also declare constants using the keyword const.Rather than explicitly
putting constant values in a program, you can name the constants using macros,
then use the names in place of the constants. By changing the definition of the
macro, you can more easily change the program:
In this example, the array x is dimensioned using the macro ARRAY_SIZE rather
than the constant 1000. Note that expressions that may use the array can also use
the macro instead of the actual constant:
Changing the dimension of x means only changing the macro for ARRAY_SIZE. The
dimension changes and so do all of the expressions that make use of the dimension.
Other Macros
#define FALSE 0
#define TRUE 1
The following macro is more complex. It has two parameters and produces an inline
expression which is equal to the maximum of its two parameters:
Use the special ## operator to form other tokens by concatenating tokens used as
actual arguments. Each instance of the ## operator is deleted and the tokens
preceding and following the ## are concatenated into a single token. If either of these
names is a formal parameter of the macro, the corresponding argument at invocation
is used. This is useful in forming unique variable names within macros.
Example 1
main()
{
int concat(fire,fly);
concat(fire,fly) = 1;
printf("%d \n",concat(fire,fly));
}
Preprocessing the preceding program yields the following:
main()
{
int firefly ;
firefly = 1;
printf("%d \n",firefly );
}
Example 2
#include <iostream.h>
#define show_me(arg) int var##arg=arg;\
cout << "var" << #arg << " is " << var##arg << "\n";
main()
{
show_me(1);
}
Preprocessing this example yields the following code for the main procedure:
main()
{
int var1=1; cout << "var" << "1" << " is " << var1 << "\n";
}
After compiling the code with CC and running the resulting executable file, you get the
following results:
var1 is 1
NOTE: The # and ## operators are only valid when using the ANSI C mode
preprocessor, which is the default preprocessor. They are not supported
when using the compatibility mode preprocessor.
In both the # and ## operations, the arguments are substituted as is, without any
intermediate expansion. After these operations are completed, the entire
replacement text is re-scanned for further macro expansions.
Preprocessor directives
Preprocessor directives are lines included in the code of our programs that are not
program statements but directives for the preprocessor. These lines are always preceded
by a hash sign (#). The preprocessor is executed before the actual compilation of code
begins, therefore the preprocessor digests all these directives before any code is generated
by the statements.
These preprocessor directives extend only across a single line of code. As soon as a
newline character is found, the preprocessor directive is considered to end. No semicolon
(;) is expected at the end of a preprocessor directive. The only way a preprocessor
directive can extend through more than one line is by preceding the newline character at
the end of the line by a backslash (\).
macro definitions (#define, #undef)
To define preprocessor macros we can use #define. Its format is:
After the preprocessor has replaced TABLE_SIZE, the code becomes equivalent to:
1 int table1[100];
2 int table2[100];
This use of #define as constant definer is already known by us from previous tutorials, but
#define can work also with parameters to define function macros:
This would replace any occurrence of getmax followed by two arguments by the
replacement expression, but also replacing each argument by its identifier, exactly as you
would expect if it was a function:
1 // function macro 5
2 #include <iostream> 7
3 using namespace std;
4
5 #define getmax(a,b) ((a)>(b)?(a):
6 (b))
7
8 int main()
9{
10 int x=5, y;
11 y= getmax(x,2);
12 cout << y << endl;
13 cout << getmax(7,x) << endl;
14 return 0;
}
Defined macros are not affected by block structure. A macro lasts until it is undefined with
the #undef preprocessor directive:
1 int table1[100];
2 int table2[200];
Function macro definitions accept two special operators (# and ##) in the replacement
sequence:
If the operator # is used before a parameter is used in the replacement sequence, that
parameter is replaced by a string literal (as if it were enclosed between double quotes)
1 #define str(x) #x
2 cout << str(test);
The operator ## concatenates two arguments leaving no blank spaces between them:
1 #define glue(a,b) a ## b
2 glue(c,out) << "test";
Because preprocessor replacements happen before any C++ syntax check, macro
definitions can be a tricky feature, but be careful: code that relies heavily on complicated
macros may seem obscure to other programmers, since the syntax they expect is on many
occasions different from the regular expressions programmers expect in C++.
These directives allow to include or discard part of the code of a program if a certain
condition is met.
#ifdef allows a section of a program to be compiled only if the macro that is specified as
the parameter has been defined, no matter which its value is. For example:
1 #ifdef TABLE_SIZE
2 int table[TABLE_SIZE];
3 #endif
In this case, the line of code int table[TABLE_SIZE]; is only compiled if TABLE_SIZE
was previously defined with #define, independently of its value. If it was not defined,
that line will not be included in the program compilation.
#ifndef serves for the exact opposite: the code between #ifndef and #endif directives
is only compiled if the specified identifier has not been previously defined. For example:
1 #ifndef TABLE_SIZE
2 #define TABLE_SIZE 100
3 #endif
4 int table[TABLE_SIZE];
In this case, if when arriving at this piece of code, the TABLE_SIZE macro has not been
defined yet, it would be defined to a value of 100. If it already existed it would keep its
previous value since the #define directive would not be executed.
The #if, #else and #elif (i.e., "else if") directives serve to specify some condition to be
met in order for the portion of code they surround to be compiled. The condition that
follows #if or #elif can only evaluate constant expressions, including macro
expressions. For example:
1 #if TABLE_SIZE>200
2 #undef TABLE_SIZE
3 #define TABLE_SIZE 200
4
5 #elif TABLE_SIZE<50
6 #undef TABLE_SIZE
7 #define TABLE_SIZE 50
8
9 #else
10 #undef TABLE_SIZE
11 #define TABLE_SIZE 100
12 #endif
13
14 int table[TABLE_SIZE];
Notice how the whole structure of #if, #elif and #else chained directives ends with
#endif.
The behavior of #ifdef and #ifndef can also be achieved by using the special operators
defined and !defined respectively in any #if or #elif directive:
The #line directive allows us to control both things, the line numbers within the code files
as well as the file name that we want that appears when an error takes place. Its format
is:
Where number is the new line number that will be assigned to the next code line. The line
numbers of successive lines will be increased one by one from this point on.
"filename" is an optional parameter that allows to redefine the file name that will be
shown. For example:
This code will generate an error that will be shown as error in file "assigning
variable", line 20.
1 #ifndef __cplusplus
2 #error A C++ compiler is required!
3 #endif
This example aborts the compilation process if the macro name __cplusplus is not
defined (this macro name is defined by default in all C++ compilers).
1 #include "file"
2 #include <file>
The only difference between both expressions is the places (directories) where the
compiler is going to look for the file. In the first case where the file name is specified
between double-quotes, the file is searched first in the same directory that includes the file
containing the directive. In case that it is not there, the compiler searches the file in the
default directories where it is configured to look for the standard header files.
If the file name is enclosed between angle-brackets <> the file is searched directly where
the compiler is configured to look for the standard header files. Therefore, standard header
files are usually included in angle-brackets, while other specific header files are included
using quotes.
If the compiler does not support a specific argument for #pragma, it is ignored - no error
is generated.
macro value
Integer value representing the current line in the source code file being
__LINE__
compiled.
A string literal containing the presumed name of the source file being
__FILE__
compiled.
A string literal in the form "Mmm dd yyyy" containing the date in which the
__DATE__
compilation process began.
A string literal in the form "hh:mm:ss" containing the time at which the
__TIME__
compilation process began.
An integer value. All C++ compilers have this constant defined to some value.
__cplusplus If the compiler is fully compliant with the C++ standard its value is equal or
greater than 199711L depending on the version of the standard they comply.
For example: