7.3. DirectivesDirectives are always introduced by a line that starts with
a
The meanings and use of these features are described in the following
sections. Make a note that the 7.3.1. The null directiveThis is simple: a plain 7.3.2. # defineThere are two ways of defining macros, one of which looks like a function and one which does not. Here is an example of each: #define FMAC(a,b) a here, then b #define NONFMAC some text here Both definitions define a macro and some replacement text, which will be used to replace later occurrences of the macro name in the rest of the program. After those definitions, they can be used as follows, with the effect of the macro replacement shown in comments: NONFMAC /* some text here */ FMAC(first text, some more) /* first text here, then some more */ For the non-function macro, its name is simply replaced by its
replacement text. The function macro is also replaced by its replacement
text; wherever the replacement text contains an identifier which is the
name of one of the macro's ‘formal parameters’, the actual text
given as the argument is used in place of the identifier in the
replacement text. The scope of the names of the formal parameters is
limited to the body of the For both forms of macro, leading or trailing white space around the replacement text is discarded. A curious ambiguity arises with macros: how do you define a non-function macro whose replacement text happens to start with the opening parenthesis character (? The answer is simple. If the definition of the macro has a space in front of the (, then it isn't the definition of a function macro, but a simple replacement macro instead. When you use function-like macros, there's no equivalent restriction. The Standard allows either type of macro to be redefined at any time,
using another # define XXX abc/*comment*/def hij # define XXX abc def hij because comment is a form of white space. The token sequence for both cases (w-s stands for a white-space token) is: # w-s define w-s XXX w-s abc w-s def w-s hij w-s 7.3.2.1. Macro substitutionWhere will occurrences of the macro name cause the replacement text
to be substituted in its place? Practically anywhere in a program that
the identifier is recognized as a separate token, except as the
identifier following the #define define XXX #define YYY ZZZ and expect the second When the identifier associated with a non-function macro is seen, it is replaced by the macro replacement tokens, then rescanned (see later) for further replacements to make. Function macros can be used like real functions; white space around the macro name, the argument list and so on, may include the newline character:
#define FMAC(a, b) printf("%s %s\n", a, b)
FMAC ("hello",
"sailor"
);
/* results in */
printf("%s %s\n", "hello", "sailor")
The ‘arguments’ of a function macro can be almost any arbitrary
token sequence. Commas are used to separate the arguments from each
other but can be hidden by enclosing them within parentheses,
#define CALL(a, b) a b
CALL(printf, ("%d %d %s\n",1, 24, "urgh"));
/* results in */
printf ("%d %d %s\n",1, 24, "urgh");
Note very carefully that the parentheses around the second argument to CALL were preserved in the replacement: they were not stripped from the text. If you want to use macros like If any argument contains no preprocessor tokens then the behaviour is undefined. The same is true if the sequence of preprocessor tokens that forms the argument would otherwise have been another preprocessor directive: #define CALL(a, b) a b /* undefined behaviour in each case.... */ CALL(,hello) CALL(xyz, #define abc def) In our opinion, the second of the erroneous uses of When a function macro is being processed, the steps are as follows:
7.3.2.2. StringizingThere is special treatment for places in the macro replacement text
where one of the macro formal parameters is found preceded by
This example demonstrates the feature:
#define MESSAGE(x) printf("Message: %s\n", #x)
MESSAGE (Text with "quotes");
/*
* Result is
* printf("Message: %s\n", "Text with \"quotes\"");
*/
7.3.2.3. Token pastingA As an example of token pasting, here is a multi-stage operation, involving rescanning (which is described next). #define REPLACE some replacement text #define JOIN(a, b) a ## b JOIN(REP, LACE) becomes, after token pasting, REPLACE becomes, after rescanning some replacement text 7.3.2.4. RescanningOnce the processing described above has occurred, the replacement text plus the following tokens of the source file is rescanned, looking for more macro names to replace. The one exception is that, within a macro's replacement text, the name of the macro itself is not expanded. Because macro replacement can be nested, it is possible for several macros to be in the process of being replaced at any one point: none of their names is a candidate for further replacement in the ‘inner’ levels of this process. This allows redefinition of existing functions as macros: #define exit(x) exit((x)+1) These macro names which were not replaced now become tokens which are immune from future replacement, even if later processing might have meant that they had become available for replacement. This prevents the danger of infinite recursion occurring in the preprocessor. The suppression of replacement is only if the macro name results directly from replacement text, not the other source text of the program. Here is what we mean: #define m(x) m((x)+1) /* so */ m(abc); /* expands to */ m((abc)+1); /* * even though the m((abc)+1) above looks like a macro, * the rules say it is not to be re-replaced */ m(m(abc)); /* * the outer m( starts a macro invocation, * but the inner one is replaced first (as above) * with m((abc)+1), which becomes the argument to the outer call, * giving us effectively */ m(m((abc+1)); /* * which expands to */ m((m((abc+1))+1); If that doesn't make your brain hurt, then go and read what the Standard says about it, which will. 7.3.2.5. NotesThere is a subtle problem when using arguments to function macros.
/* warning - subtle problem in this example */
#define SQR(x) ( x * x )
/*
* Wherever the formal parameters occur in
* the replacement text, they are replaced
* by the actual parameters to the macro.
*/
printf("sqr of %d is %d\n", 2, SQR(2));
The formal parameter of
printf("sqr of %d is %d\n", 2, ( 2 * 2 ));
The use of the parentheses should be noticed. The following example is likely to give trouble:
/* bad example */
#define DOUBLE(y) y+y
printf("twice %d is %d\n", 2, DOUBLE(2));
printf("six times %d is %d\n", 2, 3*DOUBLE(2));
The problem is that the last expression in the second printf is replaced by 3*2+2 which results in SQR(3+4) /* expands to */ ( 3+4 * 3+4 ) /* oh dear, still wrong! */ so, when formal parameters occur in the replacement text, you should
look carefully at them too. Correct versions of #define SQR(x) ((x)*(x)) #define DOUBLE(x) ((x)+(x)) Macros have a last little trick to surprise you with, as this shows.
#include <stdio.h>
#include <stdlib.h>
#define DOUBLE(x) ((x)+(x))
main(){
int a[20], *ip;
ip = a;
a[0] = 1;
a[1] = 2;
printf("%d\n", DOUBLE(*ip++));
exit(EXIT_SUCCESS);
}Example 7.1Why is this going to cause problems? Because the replacement text of
the macro refers to Despite these warnings, they provide a very useful feature, and one which will be used a lot from now on. 7.3.3. # undefThe name of any #undef NAME It isn't an error to This occasionally comes in handy. Chapter 9 points out that some library functions may actually be macros, not functions, but by undefing their names you are guaranteed access to a real function. 7.3.4. # includeThis comes in two flavours: #include <filename> #include "filename" both of which cause a new file to be read at the point where they
occur. It's as if the single line containing the directive is replaced
by the contents of the specified file. If that file contains erroneous
statements, you can reasonably expect that the errors will be reported
with a correct file name and line number. It's the compiler writer's job
to get that right. The Standard specifies that at least eight nested
levels of The effect of using brackets In general, brackets are used when you specify standard library header files, quotes are used for private header files—often specific to one program only. Although the Standard doesn't define what constitutes a valid file
name, it does specify that there must be an implementation-defined
unique way of translating file names of the form You can also write this: # define NAME <stdio.h> # include NAME to get the same effect as # include <stdio.h> but it's a rather roundabout way of doing it, and unfortunately it's
subject to implementation defined rules about how the text
between It's simpler if the replacement text for #define NAME "stdio.h" #include NAME There is no problem with implementation defined behaviour here, but the paths searched are different, as explained above. For the first case, what happens is that the token sequence which replaces NAME is (by the rules already given) < stdio . h > and for the second case "stdio.h" The second case is easy, since it's just a string-literal
which is a legal token for a Finally, the last character of a file which is being
7.3.5. Predefined namesThe following names are predefined within the preprocessor:
If the argument to There's only one minor caveat: the use of the
if(expression)
TEST(expr2);
else
statement_n;
The else will get associated with the hidden if generated by expanding
the None of the names The Standard specifies that any other reserved names will either start with an underscore followed by an upper case letter or another underscore, so you know that you are free to use any other names for your own purposes (but watch out for additional names reserved in Library header files that you may have included). 7.3.6. #lineThis is used to set the value of the built in names
Its form is # line number optional-string-literal newline The number sets the value of In fact, the sequence of tokens following 7.3.7. Conditional compilationA number of the directives control conditional compilation, which
allows certain portions of a program to be selectively compiled or
ignored depending upon specified conditions. The directives concerned
are: The way that they are used is like this: #ifdef NAME /* compile these lines if NAME is defined */ #endif #ifndef NAME /* compile these lines if NAME is not defined */ #else /* compile these lines if NAME is defined */ #endif So, These directives are most commonly used to select small fragments of C that are machine specific (when it is not possible to make the whole program completely machine independent), or sometimes to select different algorithms depending on the need to make trade-offs. The As with the other conditional statements in C, a resulting value of zero is used to represent ‘false’, anything else is ‘true’. The preprocessor always must use arithmetic with at least the ranges
defined in the
#include <limits.h>
#if ULONG_MAX+1 != 0
printf("Preprocessor: ULONG_MAX+1 != 0\n");
#endif
if(ULONG_MAX+1 != 0)
printf("Runtime: ULONG_MAX+1 != 0\n");Example 7.3It is conceivable that the preprocessor might perform arithmetic with
a greater range than that used in the target environment. In that case,
the preprocessor expression The following skeleton example illustrates the use of such constants
and also the ‘conditional else’, #define NAME 100 #if ((NAME > 50) && (defined __STDC__)) /* do something */ #elif NAME > 25 /* do something else*/ #elif NAME > 10 /* do something else */ #else /* last possibility */ #endif A word of warning. These conditional compilation directives do not obey the same scope rules as the rest of C. They should be used sparingly, unless your program is rapidly to become unreadable. It is impossible to read C when it is laced with these things every few lines. The urge to maim the author of a piece of code becomes very strong when you suddenly come across
#else
}
#endif
with no 7.3.8. #pragmaThis was the Standard Committee's way of ‘opening the back door’. It allows implementation-defined things to take place. If the implementation was not expecting what you wrote (i.e. doesn't recognize it), it is ignored. Here is a possible example: #pragma byte_align which could be used to tell the implementation that all structure members should be aligned on byte addresses - some processor architectures are able to cope with word-sized structure members aligned on byte addresses, but with a penalty in access speed being incurred. It could, of course, mean anything else that the implementation chooses it to mean. If your implementation doesn't have any special meaning for this, then it will have no effect. It will not count as an error. It will be interesting to see the sort of things that this gets used for. 7.3.9. #errorThis directive is followed by one or more tokens at the end of the line. A diagnostic message is produced by the compiler, which includes those tokens, but no further detail is given in the Standard. It might be used like this to abort a compilation on unsuitable hardware: #include <limits.h> #if CHAR_MIN > -128 #error character range smaller than required #endif which would be expected to produce some sort of meaningful compilation error and message. |
The C BookThis book is published as a matter of historical interest. Please read the copyright and disclaimer information. GBdirect Ltd provides up-to-date training and consultancy in C, Embedded C, C++ and a wide range of other subjects based on open standards if you happen to be interested. |
|||||||||||||||||||||||||||||
West Yorkshire Office
GBdirect Ltd
Training: 0800 651 0338 Please call between 0900 and 1700 (UK time) on Monday to Friday South East Regional Office
GBdirect Ltd
Training: 0800 651 0338 Please call between 0900 and 1700 (UK time) on Monday to Friday Please note: |