Manifest Constants: define

I l @ ve RuBoard

Manifest Constants: #define

The #define preprocessor directive, like all preprocessor directives, begins with a # symbol. The ANSI standard permits the # symbol to be preceded by spaces or tabs, and it allows for space between the # and the remainder of the directive. Older versions of C, however, typically require that the directive begin in the leftmost column and that there be no spaces between the # and the remainder of the directive. A directive can appear anywhere in the source file, and the definition holds from its place of appearance to the end of the file. We have used directives heavily to define symbolic, or manifest, constants in our programs, but they have more range than that, as we will show. Listing 16.1 illustrates some of the possibilities and properties of the #define directive.

Preprocessor directives run until the first newline following the # . That is, a directive is limited to one line in length. However, the combination backslash-newline is treated as a space, not an end-of-line marker, so you can spread the directive over several physical lines. These lines, however, constitute a single logical line.

Listing 16.1 The preproc.c program.
 /* preproc.c - - simple preprocessor examples */ #include <stdio.h> #define TWO 2        /* you can use comments if you like   */ #define OW "Consistency is the last refuge of the unimagina\ tive. - Oscar Wilde" /* a backslash continues a definition */                      /* to the next line                   */ #define FOUR  TWO*TWO #define PX printf("X is %d.\n", x) #define FMT  "X is %d.\n" int main(void) {    int x = TWO;    PX;    x = FOUR;    printf(FMT, x);    printf("%s\n", OW);    printf("TWO: OW\n");    return 0; } 

Each #define line (logical line, that is) has three parts . The first part is the #define directive itself. The second part is your chosen abbreviation, known as a macro or alias in the computer world. (Some programmers reserve the term macro for the macro functions we discuss later and use the term alias for the symbolic constants we are discussing now.) The macro name must have no spaces in it, and its name must conform to the same rules that C variables follow: Only letters , digits, and the underscore (_) character can be used, and the first character cannot be a digit. The third part (the remainder of the line) is termed the body (see Figure 16.1). When the preprocessor finds an example of one of your aliases within your program, it almost always replaces it with the body. (There is one exception, as we will show you in just a moment.) This process of going from a macro to a final replacement is called macro expansion . Note that you can use standard C comments on a #define line; they are ignored by the preprocessor. Also, in most systems (and the ANSI C standard), you can use the backslash (\) to extend a definition over more than one line, as shown in Listing 16.1 .

Figure 16.1. Parts of a macro definition.
graphics/16fig01.jpg

Let's run the example and see how it works:

 X is 2. X is 4. Consistency is the last refuge of the unimaginative. - Oscar Wilde TWO: OW 

Here's what happened . The statement

 int x = TWO; 

becomes

 int x = 2; 

as 2 is substituted for two . Then the statement

 PX; 

becomes

 printf("X is %d.\n", x); 

as that wholesale substitution is made. This is a new wrinkle because up to now we've used macros only to represent constants. Here you see that a macro can express any string, even a whole C expression. Note, though, that this is a constant string; PX will print only a variable named x .

The next line also represents something new. You might think that FOUR is replaced by 4 , but the actual process is this:

 x = FOUR; 

becomes

 x = TWO*TWO; 

which then becomes

 x = 2*2; 

The macro expansion process ends there. The actual multiplication takes place not while the preprocessor works, but during compilation because the C compiler evaluates all constant expressions (expressions with just constants) at compile time. The preprocessor does no calculation; it just makes the suggested substitutions very literally.

Note that a macro definition can include other macros. (Some compilers do not support this nesting feature.)

In the next line

 printf (FMT, x); 

becomes

 printf("X is %d.\n",x); 

as FMT is replaced by the corresponding string. This approach could be handy if you had a lengthy control string that you had to use several times. Alternatively, you can do the following:

 char * fmt = "X is %d.\n"; 

Then you can use fmt as the printf() control string.

In the next line, OW is replaced by the corresponding string. The double quotation marks make the replacement string a character string constant. The compiler will store it in an array terminated with a null character. Therefore,

 #define HAL 'Z' 

defines a character constant, but

 #define HAP "Z" 

defines a character string: Z\O .

In the example, we used a backslash immediately before the end of the line to extend the string to the next line:

 #define OW "Consistency is the last refuge of the unimagina\ tive. - Oscar Wilde" 

Note that the second line is flush left. Suppose, instead, we did this:

 #define OW "Consistency is the last refuge of the unimagina\ tive. - Oscar Wilde" 

Then the output would be this:

 Consistency is the last refuge of the unimagina    tive. - Oscar Wilde 

The space between the beginning of the line and tive counts as part of the string.

In general, wherever the preprocessor finds one of your macros in your program, it literally replaces it with the equivalent replacement text. If that string also contains macros, they, too, are replaced. The one exception to replacement is a macro found within double quotation marks. Therefore,

 printf("TWO: OW"); 

prints TWO: OW literally instead of printing

 2: Consistency is the last refuge of the unimaginative. - Oscar Wilde 

To print this last line, you would use this:

 printf("%d: %s\n", TWO, OW); 

Here, the macros are outside the double quotation marks.

When should you use symbolic constants? You should use them for most numbers . If the number is some constant used in a calculation, a symbolic name makes its meaning clearer. If the number is an array size, a symbolic name makes it simpler to change the array size and loop limits later. If the number is a system code for, say, EOF , a symbolic representation makes your program much more portable; just change one EOF definition. Mnemonic value, easy alterability, portability ”these features all make symbolic constants worthwhile.

Tokens

Technically, the body of a macro is considered to be a string of tokens rather than a string of characters . C preprocessor tokens are the separate "words" in the body of a macro definition. They are separated from one another by whitespace. For example, the definition

 #define FOUR 2*2 

has one token ”the sequence 2*2 ”but the definition

 #define SIX 2 * 3 

has three tokens in it: 2 , * , and 3 .

Character strings and token strings differ in how multiple spaces in a body are treated. Consider this definition:

 #define EIGHT 4    *    8 

A preprocessor that interpreted the body as a character string would replace EIGHT with 4 * 8 . That is, the extra spaces would be part of the replacement, but a preprocessor that interprets the body as tokens will replace EIGHT with three tokens separated by single spaces: 4 * 8 . In other words, the character string interpretation views the spaces as part of the body, but the token interpretation views the spaces as separators between the tokens of the body. In practice, some C compilers have viewed macro bodies as strings rather than tokens. The difference is of practical importance only for more intricate usages than what we're attempting here.

Incidentally, the C compiler takes a more complex view of tokens than the preprocessor does. The compiler understands the rules of C and doesn't necessarily require spaces to separate tokens. For instance, the C compiler would view 2*2 as three tokens because it recognizes that each 2 is a constant and the * is an operator.

Redefining Constants

Suppose you define LIMIT to be 20, and then later in the same file you define it again as 25. This process is called redefining a constant . Implementations differ on redefinition policy. Some consider it an error unless the new definition is the same as the old. Others allow redefinition, perhaps issuing a warning. The ANSI standard takes the first view, allowing redefinition only if the new definition duplicates the old.

Having the same definition means the bodies must have the same tokens in the same order. Therefore, these two definitions agree:

 #define SIX 2 * 3 #define SIX 2       *    3 

Both have the same three tokens, and the extra spaces are not part of the body. The next definition is considered different.

 #define SIX 2*3 

It has just one token, not three, so it doesn't match. If you want to redefine a macro, use the #undef directive, which we discuss later.

If you do have constants that you need to redefine, it might be easier to use the const keyword and scope rules to accomplish that end.

I l @ ve RuBoard


C++ Primer Plus
C Primer Plus (5th Edition)
ISBN: 0672326965
EAN: 2147483647
Year: 2000
Pages: 314
Authors: Stephen Prata

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net