The #define and #undef Directives

Submitted by tushar pramanick on Mon, 03/11/2013 - 00:03

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.

Related Items

মডুলার C প্রোগ্রামিং (Modular C Programming)

কেবল মাত্র একটি ফাংশন দিয়ে কোনো বড়ো জটিল সমস্যা সমাধানের চেষ্টা করা ভাল প্রোগ্রামিংয়ের পদ্ধতি নয়। সঠিক পদ্ধতি হ'ল সমস্যাটিকে কয়েকটি ছোট ছোট এবং সরল টুকরো করে ফেলা যাতে তা আরও বিশদে বোঝা যায় । তারপরে এই ছোট এবং সরল সমস্যাগুলি সমাধান করার জন্য ছোট ছোট ফাংশন ব্লক তৈরি করা এবং পরে সেগুলি নিয়মানুযায়ী সংযোজিত করা ।

Programming Style

Programming Style

In this section, I'd like to briefly highlight some points that will help you write clean programs that can easily be read, understood, and maintained.

Exercises : Answer the following Question

To help solidify your understanding of this hour's lesson, you are encouraged to answer the quiz questions and finish the exercises provided in the Workshop before you move to the next lesson.

Question and Answer

    Q Is the C preprocessor part of the C compiler?

    A No. The C preprocessor is not part of the C compiler. With its own line-oriented grammar and syntax, the C preprocessor runs before the compiler in order to handle named constants, macros, and inclusion of files.

Compiling Your Code Under Conditions

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 is useful, especially when you're testing a piece of new code or debugging a portion of code.