The #define and #undef Directives
The #define directive is the most common preprocessor directive, which tells the preprocessor to replace every occurrence of a particular character string (that is, a macro name) with a specified value (that is, a macro body).
The syntax for the #define directive is
#define macro_name macro_body
Here macro_name is an identifier that can contain letters, numerals, or underscores. macro_body may be a string or a data item, which is used to substitute each macro_name found in the program.
As mentioned earlier, the operation to replace occurrences of macro_name with the value specified by macro_body is known as macro substitution or macro expansion.
The value of the macro body specified by a #define directive can be any character string or number. For example, the following definition associates STATE_NAME with the string "Texas" (including the quotation marks):
#define STATE_NAME "Texas"
Then, during preprocessing, all occurrences of STATE_NAME will be replaced by "Texas".
Likewise, the following statement tells the C preprocessor to replace SUM with the string (12 + 8):
#define SUM (12 + 8)
On the other hand, you can use the #undef directive to remove the definition of a macro name that has been previously defined.
The syntax for the #undef directive is
#undef macro_name
Here macro_name is an identifier that has been previously defined by a #define directive.
The #undef directive "undefines" a macro name. For instance, the following segment of code:
#define STATE_NAME "Texas"
printf("I am moving out of %s.\n", STATE_NAME);
#undef STATE_NAME
defines the macro name STATE_NAME first, and uses the macro name in the printf() function; then it removes the macro name.
Defining Function-Like Macros with #define
You can specify one or more arguments to a macro name defined by the #define directive, so that the macro name can be treated like a simple function that accepts arguments.
For instance, the following macro name, MULTIPLY, takes two arguments:
#define MULTIPLY(val1, val2) ((val1) * (val2))
When the following statement:
result = MULTIPLY(2, 3) + 10;
is preprocessed, the preprocessor substitutes the expression 2 for val1 and 3 for val2, and then produces the following equivalent:
result = ((2) * (3)) + 10;
The program in Listing 23.1 is an example of using the #define directive to perform macro substitution.
TYPE
Listing 23.1. Using the #define directive.
1: /* 23L01.c: Using #define */
2: #include <stdio.h>
3:
4: #define METHOD "ABS"
5: #define ABS(val) ((val) < 0 ? -(val) : (val))
6: #define MAX_LEN 8
7: #define NEGATIVE_NUM -10
8:
9: main(void)
10: {
11: char *str = METHOD;
12: int array[MAX_LEN];
13: int i;
14:
15: printf("The orignal values in array:\n");
16: for (i=0; i<MAX_LEN; i++){
17: array[i] = (i + 1) * NEGATIVE_NUM;
18: printf("array[%d]: %d\n", i, array[i]);
19: }
20:
21: printf("\nApplying the %s macro:\n", str);
22: for (i=0; i<MAX_LEN; i++){
23: printf("ABS(%d): %3d\n", array[i], ABS(array[i]));
24: }
25:
26: return 0;
27: }
OUTPUT
The following output appears on the screen after you run the executable 23L01.exe of the program in Listing 23.1:
C:\app>23L01
The orignal values in array:
array[0]: -10
array[1]: -20
array[2]: -30
array[3]: -40
array[4]: -50
array[5]: -60
array[6]: -70
array[7]: -80
Applying the ABS macro:
ABS(-10): 10
ABS(-20): 20
ABS(-30): 30
ABS(-40): 40
ABS(-50): 50
ABS(-60): 60
ABS(-70): 70
ABS(-80): 80
C:\app>
ANALYSIS
The purpose of the program in Listing 23.1 is to define different macro names, including a function-like macro, and use them in the program.
In lines 4_7, four macro names, METHOD, ABS, MAX_LEN, and NEGATIVE_NUM are defined with the #define directive. Among them, ABS can accept one argument. The definition of ABS in line 5 checks the value of the argument and returns the absolute value of the argument. Note that the conditional operator ?: is used to find the absolute value for the incoming argument. (The ?: operator was introduced in Hour 8, "More Operators.")
Then, inside the main() function, the char pointer str is defined and assigned with METHOD in line 11. As you can see, METHOD is associated with the string "ABS". In line 12, an int array called array is defined with the element number specified by MAX_LEN.
In lines 16_19, each element of array is initialized with the value represented by the (i + 1) * NEGATIVE_NUM expression that produces a series of negative integer numbers.
The for loop in lines 22_24 applies the function-like macro ABS to each element of array and obtains the absolute value for each element. Also, all absolute values are printed on the screen. The output from the program in Listing 23.1 proves that each macro defined in the program works very well.
Nested Macro Definitions
A previously defined macro can be used as the value in another #define statement. The following is an example:
#define ONE 1
#define TWO (ONE + ONE)
#define THREE (ONE + TWO)
result = TWO * THREE;
Here the macro ONE is defined to be equivalent to the value 1, and TWO is defined to be equivalent to (ONE + ONE), where ONE is defined in the previous macro definition. Likewise, THREE is defined to be equivalent to (ONE + TWO), where both ONE and TWO are previously defined.
Therefore, the assignment statement following the macro definitions is equivalent to the following statement:
result = (1 + 1) * (1 + (1 + 1));
WARNING
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
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)
result = (12 + 8) * 10;
and produces the result 200, which is likely what you want.
- 7 views