|
|
|
|
Lesson#5
|
Preprocessor Directives
|
|
|
|
Preprocessor.....................................................................................................2
Preprocessor directives: #ifdef and #ifndef
....................................................2
Prevent multiple definitions in header
files.....................................................2
Turning debugging code off and on
...............................................................2
Some Preprocessor
directives...........................................................................3
#define....................................................................................................3
Example: macro #defines
..............................................................................3
#error
......................................................................................................3
#include
..................................................................................................3
Conditional Compilation - #if, #else, #elif, and
#endif........................................4
#ifdef and #ifndef
....................................................................................4
#undef.....................................................................................................4
#line........................................................................................................4
#pragma
.................................................................................................4
The # and ## Preprocessor Operators
..............................................................5
Macros
..............................................................................................................5
Standard Predefined Macros
.........................................................................5
__FILE__................................................................................................6
__LINE__................................................................................................6
__DATE__..............................................................................................6
__TIME__...............................................................................................6
__STDC__..............................................................................................6
__STDC_VERSION__............................................................................7
__STDC_HOSTED__.............................................................................7
__cplusplus.............................................................................................7
Summary...........................................................................................................7
Tips
...................................................................................................................7
Preprocessor Directives 2
Preprocessor
The preprocessor is a program that runs prior to compilation and potentially
modifies a
source code file. It may add code in response to the #include directive,
conditionally
include code in response to #if, #ifdef, #ifndef directives or define
constants using the
#define directive.
As defined by the ANSI standard, the C preprocessor contains the following
directives:
#if #ifdef #ifndef #else #elif #include #define #undef #line #error #pragma
Preprocessor directives: #ifdef and #ifndef
The #ifdef (if defined) and #ifndef (if not defined) preprocessor commands
are used to
test if a preprocessor variable has been "defined".
Prevent multiple definitions in header files
When there are definitions in a header file that can not be made twice, the
code below
should be used. A header file may be included twice because more than one
other
“include file” includes it, or an included file includes it and the source
file includes it
again.
To prevent bad effects from a double include, it is common to surround the
body in the
include file with the following:
#ifndef MYHEADERFILE_H
#define MYHEADERFILE_H
. . . // This will be seen by the compiler only once
#endif /* MYHEADERFILE_H */
Turning debugging code off and on
Debugging code is necessary in programs; however, it is not
usually appropriate to leave
it in the delivered code. The preprocessor #ifdef command can surround the
debugging
code. If DEBUG is defined as below (probably in an include file) all
debugging statement
surrounded by the #ifdef DEBUG statement will be active. However, if it
isn't defined,
none of the statements will make it through the preprocessor.
#define DEBUG
. . .
#ifdef DEBUG
. . . // debugging output
#endif
Preprocessor Directives 3
Some Preprocessor directives
• #define
#define defines an identifier (the macro name) and a string (the macro
substitution) which
will be substituted for the identifier each time the identifier is
encountered in the source
file. Once a macro name has been defined, it may be used as part of the
definition of
other macro names.
If the string is longer than one line, it may be continued by placing a
backslash on the end
of the first line. By convention, C programmers use uppercase for defined
identifiers.
Example: macro #defines
#define TRUE 1
#define FALSE 0
The macro name may have arguments, in which case every time the macro
name is
encountered; the arguments associated with it are replaced by the actual
arguments found
in the program, as in:
#define ABS(a) (a)<0 ? -(a) : (a)
...
printf("abs of -1 and 1: %d %d", ABS(-1), ABS(1));
Such macro substitutions in place of real functions increase the speed of
the code at the
price of increased program size.
• #error
#error forces the compiler to stop compilation. It is used primarily for
debugging. The
general form is:
#error error_message
When the directive is encountered, the error message is displayed, possibly
along with
other information (depending on the compiler).
• #include
#include instructs the compiler to read another source file, which must be
included
between double quotes or angle brackets. Examples are:
#include "stdio.h"
#include <stdio.h>
Both of these directives instruct the compiler to read and compile the named
header file.
If a file name is enclosed in angle brackets, the file is searched for as
specified by the
creator of the compiler. If the name is enclosed in double quotes, the file
is searched for
Preprocessor Directives 4
in an implementation-defined manner, which generally means searching the
current
directory. (If the file is not found, the search is repeated as if the name
had been enclosed
in angle brackets.)
Conditional Compilation - #if, #else, #elif, and
#endif
Several directives control the selective compilation of portions of the
program code, viz,
#if, #else, #elif, and #endif.
The general form of #if is:
#if constant_expression
statement sequence
#endif
#else works much like the C keyword else. #elif means "else if" and
establishes an ifelse-
if compilation chain.
Amongst other things, #if provides an alternative method of "commenting out"
code. For
example, in
#if 0
printf("#d",total);
#endif
the compiler will ignore printf("#d",total);.
•
#ifdef and #ifndef
#ifdef means "if defined", and is terminated by an #endif. #ifndef means "if
not defined".
• #undef
#undef removes a previously defined definition.
• #line
line changes the contents of __LINE__ (which contains the line number of the
currently
compiled code) and __FILE__ (which is a string which contains the name of
the source
file being compiled), both of which are predefined identifiers in the
compiler.
• #pragma
The #pragma directive is an implementation-defined directive which allows
various
instructions to be given to the compiler i.e. it allows a directive to be
defined.
The #pragma directive is the method specified by the C standard for
providing additional
information to the compiler, beyond what is conveyed in the language itself.
Three forms
of this directive (commonly known as pragmas) are specified by the 1999 C
standard. A
C compiler is free to attach any meaning it likes to other pragmas.
Preprocessor Directives 5
The # and ## Preprocessor Operators
The # and ## preprocessor operators are used when using a macro #define. The
#
operator turns the argument it precedes into a quoted string. For example,
given:
#define mkstr(s) # s
the preprocessor turns the line
printf(mkstr(I like C);
into
printf("I like C");
The ## operator concatenates two tokens. For example, given:
#define concat(a, b) a ## b
int xy=10;
printf("%d",concat(x, y);
the preprocessor turns the last line into:
printf("%d", xy);
Macros
A macro is a fragment of
code which has been given a name. Whenever the name is used,
it is replaced by the contents of the macro. There are two kinds of macros.
They differ
mostly in what they look like when they are used.
Object-like macros resemble
data
objects when used, function-like
macros resemble function calls.
You may define any valid identifier as a macro, even if it is a C keyword.
The
preprocessor does not know anything about keywords. This can be useful if
you wish to
hide a keyword such as const from an older compiler that does not understand
it.
However, the preprocessor operator defined can never be defined as a macro,
and C++'s
named operators cannot be macros when you are compiling C++.
To define a macro that takes arguments, you use the #define command with a
list of
parameters in parentheses after the name of the macro. The parameters may be
any valid
C identifiers separated by commas at the top level (that is, commas that
aren't within
parentheses) and, optionally, by white-space characters. The left
parenthesis must follow
the macro name immediately, with no space in between.
For example, here's a macro that computes the maximum of two numeric values:
#define min(X, Y) ((X)>(Y) ? (X):(Y))
Standard Predefined Macros
The standard predefined macros are specified by the C and/or C++
language standards, so
they are available with all compilers that implement those standards. Older
compilers
may not provide all of them. Their names all start with double underscores.
Preprocessor Directives 6
• __FILE__
This macro expands to the name of the current input file, in the form of a C
string
constant. This is the path by which the preprocessor opened the file, not
the short names
specified in #include or as the input file name argument. For example,
"/usr/local/include/myheader.h" is a possible expansion of this macro.
•
__LINE__
This macro expands to the current input line number, in the form of a
decimal integer
constant. While we call it a predefined macro, it's a pretty strange macro,
since its
"definition" changes with each new line of source code.
__FILE__ and __LINE__ are useful in generating an error message to
report an inconsistency
detected by the program; the message can state the source line at which the
inconsistency
was detected. For example,
fprintf (stderr, "Internal error: "
"negative string length "
"%d at %s, line %d.",
length, __FILE__, __LINE__);
An #include directive changes the expansions of __FILE__ and __LINE__ to
correspond to
the included file. At the end of that file, when processing resumes on the
input file that
contained the #include directive, the expansions of __FILE__ and __LINE__
revert to the values
they had before the #include (but __LINE__ is then incremented by one as
processing moves
to the line after the #include).
• __DATE__
This macro expands to a string constant that describes the date on which the
preprocessor
is being run. The string constant contains eleven characters and looks like
"Feb 12 1996".
If the day of the month is less than 10, it is padded with a space on the
left.
•
__TIME__
This macro expands to a string constant that describes the time at which the
preprocessor
is being run. The string constant contains eight characters and looks like
"23:59:01".
•
__STDC__
In normal operation, this macro expands to the constant 1, to signify that
this compiler
conforms to ISO Standard C.
Preprocessor Directives 7
•
__STDC_VERSION__
This macro expands to the C Standard's version number, a long integer
constant of the
form yyyymmL where yyyy and mm are the year and month of the Standard
version.
This signifies which version of the C Standard the compiler conforms to.
This macro is not defined if the -traditional option is used, nor when
compiling C++ or
Objective-C.
•
__STDC_HOSTED__
This macro is defined, with value 1, if the compiler's target is a
hosted environment. A
hosted environment has the complete facilities of the standard C
available.
• __cplusplus
This macro is defined when the C++ compiler is in use. You can use
__cplusplus to test
whether a header is compiled by a C compiler or a C++ compiler. This macro
is similar
to __STDC_VERSION__, in that it expands to a version number.
Tips
• Do use the preprocessor directives as
much as possible in your programme as it
makes the programme more robust.
Preprocessor Directives 8
• Using the #defined, #ifndef directives helps
in Prevent multiple definitions in
header files.
• Conditional compilation with the use of
preprocessor directives provides a very
easy way for turning the debug code on and off.
• A macro is a fragment of code which has been
given a name. Whenever the name
is used, it is replaced by the contents of the macro.
• Macros can be used for writing clear and
easily comprehensible code.
• Do remember that whenever the macro name is
used, it is replaced by the contents
of the macro.
Summary
The preprocessor is a program that runs prior to compilation and
potentially modifies a
source code file. It may add code in response to the #include directive,
conditionally
include code in response to #if, #ifdef, #ifndef directives or define
constants using the
#define directive.
A simple macro is a kind of abbreviation. It is a name which stands for a
fragment of
code. Some standard pre-defined Macros include __FILE__, __LINE__, __DATE__,
__TIME__ etc.
|
|
|
|