Sams Teach Yourself C in 24 Hours (63 page)

BOOK: Sams Teach Yourself C in 24 Hours
13.85Mb size Format: txt, pdf, ePub

Therefore, the assignment statement following the macro definitions is expanded to the following statement:

result = (1 + 1) * (1 + (1 + 1));

When you are using the #define directive with a macro body that is an

expression, you need to enclose the macro body in parentheses. For example, if the macro definition is

#define SUM 12 + 8

then the following statement:

result = SUM * 10;

becomes this:

result = 12 + 8 * 10;

which assigns 92 to result.

However, if you enclose the macro body in parentheses like this:

#define SUM (12 + 8)

then the assignment statement becomes this:

result = (12 + 8) * 10;

and produces the result 200, which is likely what you want.

29 067231861x CH23 1/25/00 11:03 AM Page 397

Compiling Programs: The C Preprocessor

397

Compiling Your Code Under Conditions

You can select portions of your C program that you want to compile by using a set of preprocessor directives. This technique is called
conditional compilation
. This is useful, especially when you’re testing a piece of new code or debugging a portion of code.

The
#ifdef
and
#endif
Directives

The #ifdef and #endif directives control whether a given group of statements is to be
23

included as part of your program.

The general form to use the #ifdef and #endif directives is

#ifdef macro_name

statement1

statement2

. . .

statementN

#endif

Here macro_name is any character string that can be defined by a #define directive.

statement1, statement2, and statementN are statements that are included in the program only if macro_name has already been defined. If maccro_name has not been defined, statement1, statement2, and everything up to statementN skipped.

Unlike an if statement in C, the statements under the control of the #ifdef directive are not enclosed in braces; instead, the #endif directive must be used to mark the end of the

#ifdef block.

For instance, the #ifdef directive in the following code segment:

. . .

#ifdef DEBUG

printf(“The contents of the string pointed to by str: %s\n”, str);

#endif

. . .

indicates that if the macro name DEBUG is defined, the printf() function in the statement following the #ifdef directive is included in the program. The compiler will compile the statement so that the contents of a string pointed to by str will be printed by the statement. However if DEBUG has not been defined, the printf() call will be entirely left out of your compiled program.

The
#ifndef
Directive

The #ifndef directive enables you to define code that is to be executed when a particular macro name is not defined.

29 067231861x CH23 1/25/00 11:03 AM Page 398

398

Hour 23

The general format to use #ifndef is the same as for #ifdef:

#ifndef macro_name

statement1

statement2

. . .

statementN

#endif

Here macro_name, statement1, statement2, and statementN have the same meanings as those in the form of #ifdef introduced in the previous section. Again, the #endif directive is needed to mark the end of the #ifndef block.

Listing 23.2 contains a program that demonstrates how to use the #ifdef, #ifndef, and

#endif directives together.

TYPE

LISTING 23.2

Using the #ifdef, #ifndef, and #endif Directives

1: /* 23L02.c: Using #ifdef, #ifndef, and #endif */

2: #include

3:

4: #define UPPER_CASE 0

5: #define NO_ERROR 0

6:

7: main(void)

8: {

9: #ifdef UPPER_CASE

10: printf(“THIS LINE IS PRINTED OUT,\n”);

11: printf(“BECAUSE UPPER_CASE IS DEFINED.\n”);

12: #endif

13: #ifndef LOWER_CASE

14: printf(“\nThis line is printed out,\n”);

15: printf(“because LOWER_CASE is not defined.\n”);

16: #endif

17:

18: return NO_ERROR;

19: }

The following output is shown on the screen after the executable 23L02.exe is created and run on my computer:

THIS LINE IS PRINTED OUT,

OUTPUT
BECAUSE UPPER_CASE IS DEFINED.

This line is printed out,

because LOWER_CASE is not defined.

The purpose of the program in Listing 23.2 is to use #ifdef and #ifndef direc-ANALYSIS tives to control whether a message will be displayed.

29 067231861x CH23 1/25/00 11:03 AM Page 399

Compiling Programs: The C Preprocessor

399

Two macro names, UPPER_CASE and NO_ERROR, are defined in lines 4 and 5.

The #ifdef directive in line 9 checks whether the UPPER_CASE macro name has been defined. Because the macro name has been defined in line 4, the two statements in lines 10 and 11 (until the #endif directive in line 12 marks the end of the #ifdef block) are included in the compiled program.

In line 13, the #ifndef directive tells the preprocessor to include the two statements in lines 14 and 15 in the program if the LOWER_CASE macro name has not been defined. As
23

you can see, LOWER_CASE is not defined in the program at all. Therefore, the two statements in lines 14 and 15 are compiled as part of the program.

The output from running the program in Listing 23.2 shows that the printf() functions in lines 10, 11, 14, and 15 are compiled and executed accordingly, under the control of the #ifdef and #ifndef directives. You can try modifying the program by changing line 4 so that it defines LOWER_CASE rather than UPPER_CASE. The #ifdef and #ifndef directives will then remove all four printf() calls from the program.

The
#if
,
#elif
, and
#else
Directives

The #if directive specifies that certain statements are to be included only if the value represented by the conditional expression is nonzero. The conditional expression can be an arithmetic expression.

The general form to use the #if directive is

#if expression

statement1

statement2

. . .

statementN

#endif

Here expression is the conditional expression to be evaluated. statement1, statement2, and statementN represent the code to be included if expression is nonzero.

Note that the #endif directive is included at the end of the definition to mark the end of the #if block, as it does for an #ifdef or #ifndef block.

In addition, the #else directive provides an alternative to choose. The following general form uses the #else directive to put statement_1, statement_2, and statement_N into the program if expression is zero:

#if expression

statement1

statement2

. . .

29 067231861x CH23 1/25/00 11:03 AM Page 400

400

Hour 23

statementN

#else

statement_1

statement_2

. . .

statement_N

#endif

Again, the #endif directive is used to mark the end of the #if block.

Also, a macro definition can be used as part of the conditional expression evaluated by the #if directive. If the macro is defined, it has a nonzero value in the expression; otherwise, it has the value 0.

For example, look at the following portion of code:

#ifdef DEBUG

printf(“The value of the debug version: %d\n”, debug);

#else

printf(“The value of the release version: %d\n”, release);

#endif

If DEBUG has been defined by a #define directive, the value of the debug version is printed out by the printf() function in the following statement:

printf(“The value of the debug version: %d\n”, debug);

Otherwise, if DEBUG has not been defined, the following statement is executed: printf(“The value of the release version: %d\n”, release);

Now consider another example:

#if 1

printf(“The line is always printed out.\n”);

#endif

The printf() function is always executed because the expression 1 evaluated by the #if directive never returns 0.

In the following example:

#if MACRO_NAME1 || MACRO_NAME2

printf(“MACRO_NAME1 or MACRO_NAME2 is defined.\n”);

#else

printf(“MACRO_NAME1 and MACRO_NAME2 are not defined.\n”);

#endif

the logical operator || is used, along with MACRO_NAME1 and MACRO_NAME2 in the expression evaluated by the #if directive. If one of the macro names, MACRO_NAME1 or MACRO_NAME2, has been defined, the expression evaluates to a nonzero value; otherwise, 0

is produced.

29 067231861x CH23 1/25/00 11:03 AM Page 401

Compiling Programs: The C Preprocessor

401

The C preprocessor has another directive, #elif, which stands for “else if.” You can use

#if and #elif together to build an if-else-if chain for multiple conditional compilation.

The program shown in Listing 23.3 is an example of using the #if, #elif, and #else directives.

TYPE

LISTING 23.3

Using the #if, #elif, and #else Directives

23

1: /* 23L03.c: Using #if, #elif, and #else */

2: #include

3:

4: #define C_LANG ‘C’

5: #define B_LANG ‘B’

6: #define NO_ERROR 0

7:

8: main(void)

9: {

10: #if C_LANG == ‘C’ && B_LANG == ‘B’

11: #undef C_LANG

12: #define C_LANG “I know the C language.\n”

13: #undef B_LANG

14: #define B_LANG “I know BASIC.\n”

15: printf(“%s%s”, C_LANG, B_LANG);

16: #elif C_LANG == ‘C’

17: #undef C_LANG

18: #define C_LANG “I only know C language.\n”

19: printf(“%s”, C_LANG);

20: #elif B_LANG == ‘B’

21: #undef B_LANG

22: #define B_LANG “I only know BASIC.\n”

23: printf(“%s”, B_LANG);

24: #else

25: printf(“I don’t know C or BASIC.\n”);

26: #endif

27:

28: return NO_ERROR;

29: }

After the executable 23L03.exe is created and run, the following output is displayed on the screen of my computer:

I know C language.

OUTPUT
I know BASIC.

The purpose of the program in Listing 23.3 is to use the #if, #elif, and #else
ANALYSIS
directives to select portions of code that are going to be compiled.

29 067231861x CH23 1/25/00 11:03 AM Page 402

402

Hour 23

Inside the main() function, the #if directive in line 10 evaluates the conditional expression C_LANG == ‘C’ && B_LANG == ‘B’. If the expression evaluates to nonzero, statements in lines 11–15 are selected to be compiled.

In line 11 the #undef directive is used to remove the C_LANG macro name. Line 12 then redefines C_LANG with the string “I know the C language.\n”. Likewise, line 13

removes the B_LANG macro name and line 14 redefines B_LANG with another character string. The printf() call in line 15 prints the two newly assigned strings associated with C_LANG and B_LANG.

The #elif directive in line 16 starts to evaluate the expression C_LANG == ‘C’ if the expression in line 10 has evaluated to 0. If the C_LANG == ‘C’ expression evaluates to nonzero, the statements in lines 17–19 are compiled.

If, however, the expression in line 16 also fails to evaluate to a nonzero value, the B_LANG

== ‘B’ expression is evaluated by another #elif directive in line 20. The statements in lines 21–23 are skipped, and the statement in line 25 is compiled finally if the B_LANG ==

‘B’ expression evaluates to 0.

In line 26 the #endif directive marks the end of the #if block that started on line 10.

From the program in Listing 23.3 you can tell that C_LANG and B_LANG have been properly defined in lines 4 and 5. Therefore, the statements in lines 11–15 are selected as part of the program and compiled by the C compiler. The two character strings assigned to C_LANG and B_LANG during the redefinition are displayed after the program in Listing 23.3 is executed.

You can change the value of the macros C_LANG and B_LANG to experiment with other executions of the program.

Nested Conditional Compilation

According to the ANSI C standard, the #if and #elif directives can be nested at least eight levels.

For example, the #if directive is nested in the following code segment:

#if MACRO_NAME1

#if MACRO_NAME2

#if MACRO_NAME3

printf(“MACRO_NAME1, MACRO_NAME2, and MACRO_NAME3\n”);

#else

printf(“MACRO_NAME1 and MACRO_NAME2\n”);

#endif

#else

printf(“MACRO_NAME1\n”);

29 067231861x CH23 1/25/00 11:03 AM Page 403

Compiling Programs: The C Preprocessor

403

#endif

#else

printf(“No macro name defined.\n”);

#endif

Here the #if directive is nested to three levels. Note that each #else or #endif is associated with the nearest #if.

Now let’s have a look at another example in Listing 23.4, in which the #if directives are nested.

23

TYPE

LISTING 23.4

Nesting the #if Directive

1: /* 23L04.c: Nesting #if */

2: #include

3:

4: /* macro definitions */

5: #define ZERO 0

6: #define ONE 1

7: #define TWO (ONE + ONE)

8: #define THREE (ONE + TWO)

9: #define TEST_1 ONE

10: #define TEST_2 TWO

11: #define TEST_3 THREE

12: #define MAX_NUM THREE

13: #define NO_ERROR ZERO

14: /* function declaration */

15: void StrPrint(char **ptr_s, int max);

16: /* the main() function */

Other books

Broken & Burned by A.J. Downey
Fire and Ice by Nell Harding
Wicked Fall by Sawyer Bennett
Hare Sitting Up by Michael Innes
The Custom of the Country by Edith Wharton
Being Dead by Vivian Vande Velde
Mason: #6 (Allen Securities) by Madison Stevens
The Bloody Meadow by William Ryan
The Gate of Heaven by Gilbert Morris