Macro Definitions
The
macros that we've been using since are known as simple macros, because
they have no parameters. The preprocessor also supports parameterized macros.
We'll look first at simple macros, then at parameterized macros. After covering
them separately, we'll examine properties shared by both.
Simple Macros
The
definition of a simple macro (or object-like macro,
as it's called in the C standard) has the form
#define
identifier replacement-list
replacement-list
is any sequence of preprocessing tokens, which are similar to the
tokens discussed before. Whenever we use the term "token" it means "preprocessing token."
A
macro's replacement list may include identifiers, keywords, numeric constants,
character constants, string literals, operators, and punctuation. When it
encounters a macro definition, the preprocessor makes a note that identifier
represents replacement-list; wherever identifier appears later
in the file, the preprocessor substitutes replacement-list.
The # Operator
Macro definitions may contain two special operators, # and
##. Neither operator is recognized by the compiler; instead, they're executed
during preprocessing.
The
# operator converts a macro argument into a string literal; it can appear only
in the replacement list of a parameterized macro. (The operation performed by #
is known as "stringization," a term that I'm sure you won't find in
the dictionary.)
There
are a number of uses for #; let's consider just one. Suppose that we decide to
use the PRINT_INT macro during debugging as a convenient way to print
the values of integer variables and expressions. The # operator makes it possible
for PRINT_INT to label each value that it prints.
The
## Operator
The
## operator can "paste" two tokens (identifiers, for example)
together to form a single token. (Not surprisingly, the ## operation is known
as "token-pasting") If one of the operands is a macro parameter,
pasting occurs after the parameter has been replaced by the corresponding
argument.
Predefined
Macros
C has several predefined macros. Each macro represents
an integer constant or string literal. As Table below shows, these macros
provide information about the current compilation or about the compiler itself.
Name
|
Description
|
__LINE__
|
Line number of file being compiled
|
__FILE__
|
Name of file being compiled
|
__DATE__
|
Date of compilation (in the form "Mmm dd yyyy")
|
__TIME__
|
Time of compilation (in the form "hh:mm:
ss")
|
__STDC__
|
1 if the compiler conforms to the C standard (C89 or C99)
|
Conditional
Compilation
The
C preprocessor recognizes a number of directives that support conditional
compilation—the inclusion or exclusion of a section of program text
depending on the outcome of a test performed by the preprocessor.
The #if and #endif Directives
Suppose we're in the process of debugging a program. We'd
like the program to print the values of certain variables, so we put calls of
printf in critical parts of the program. Once we've located the bugs, it's
often a good idea to let the printf calls remain, just in case we need them
later. Conditional compilation allows us to leave the calls in place, but have
the compiler ignore them.
In general, the #if directive has the form
# if constant-expression
The #endif directive is even simpler
#endif
Miscellaneous Directives
we'll
take a brief look at the #error, #line, and #pragma directives. These
directives are more specialized than the ones we've already examined, and
they're used much less frequently.
The #error
Directive
The #error directive has the form
#error message
where
message is any sequence of tokens. If the preprocessor encounters an terror
directive, it prints an error message which must include message. The
exact form of the error message can vary from one compiler to another; it might
be something like
Error directive: message
or
perhaps just
# error message
Encountering
an terror directive indicates a serious flaw in the program; some compilers
immediately terminate compilation without attempting to find other errors.
#error
directives are frequently used in conjunction with conditional compilation to
check for situations that shouldn't arise during a normal compilation. For
example, suppose that we want to ensure that a program can't be compiled on a
machine whose int type isn't capable of storing numbers up to 100,000.
The largest possible int value is represented by the INT_MAX
macro, so all we need do is invoke an #error directive if INT_MAX
isn't at least 100.000.
The
#pragma Directive
The #pragma directive provides a way to request special
behavior from the compiler. This directive is most useful for programs that
are unusually large or that need to take advantage of the capabilities of a
particular compiler. The #pragma directive has the form
#pragma
tokens
where tokens are arbitrary tokens. #pragma directives
can be very simple (a single token) or they can be much more elaborate.
No comments:
Post a Comment