Chapter 6 - Defines and Macros DEFINES AND MACROS ARE AIDS TO CLEAR PROGRAMMING Load and display the file named DEFINE.C for your first look at some defines and macros. Notice the first four lines 2 through 5 of the program, each starting with the word "#define". This is the way all defines and macros are defined. Before the actual compilation starts, the compiler goes through a preprocessor pass to resolve all of the defines. In the present case, it will find every place in the program where the combination "START" is found and it will simply replace it with the 0 since that is the definition. The compiler itself will never see the word "START", so as far as the compiler is concerned, the zeros were always there. Note that if the word "START" appears in a text string or a comment, it will be ignored and unchanged. It should be clear to you by now that putting the word "START" in your program instead of the numeral 0 is only a convenience to you and actually acts like a comment since the word "START" helps you to understand what the zero is used for. In the case of a very small program, such as that before you, it doesn't really matter what you use. If, however, you had a 2000 line program before you with 27 references to the "START", it would be a completely different matter. If you wanted to change all of the "START"s in the program to a new number, it would be simple to change the one #define, but difficult to find and change all of the references to it manually, and possibly disastrous if you missed one or two of the references. In the same manner, the preprocessor will find all occurrences of the word "ENDING" and change them to 9, then the compiler will operate on the changed file with no knowledge that "ENDING" ever existed. It is a fairly common practice in C programming to use all capital letters for a symbolic constant such as "START" and "ENDING" and use all lower case letters for variable names. You can use any method you choose since it is mostly a matter of personal taste. IS THIS REALLY USEFUL? When we get to the chapters discussing input and output, we will need an indicator to tell us when we reach the end-of-file of an input file. Since different compilers use different numerical values for this, although most use either a zero or a minus 1, we will write the program with a Page 43 Chapter 6 - Defines and Macros "define" to define the EOF used by our particular compiler. If at some later date, we change to a new compiler, it is a simple matter to change this one "define" to fix the entire program. In Turbo C, the EOF is defined in the STDIO.H file on line 44. You can observe this for yourself by listing this file. WHAT IS A MACRO? A macro is nothing more than another define, but since it is capable of at least appearing to perform some logical decisions or some math functions, it has a unique name. Consider line 4 of the program on your screen for an example of a macro. In this case, anytime the preprocessor finds the word "MAX" followed by a group in parentheses, it expects to find two terms in the parentheses and will do a replacement of the terms into the second definition. Thus the first term will replace every "A" in the second definition and the second term will replace every "B" in the second definition. When line 13 of the program is reached, "index" will be substituted for every "A", and "count" will be substituted for every "B". But this replaceing will not take place in string literals or comments. Remembering the cryptic construct we studied a couple of chapters ago will reveal that "mx" will receive the maximum value of "index" or "count". In like manner, the "MIN" macro will result in "mn" receiving the minimum value of "index" or "count". The results are then printed out. There are a lot of seemingly extra parentheses in the macro definition but they are not extra, they are essential. We will discuss the extra parentheses in our next program. Compile and run DEFINE.C. LETS LOOK AT A WRONG MACRO Load the file named MACRO.C and display it on your screen for a better look at a macro and its use. The second line defines a macro named "WRONG" that appears to get the cube of "A", and indeed it does in some cases, but it fails miserably in others. The second macro named "CUBE" actually does get the cube in all cases. Consider the program itself where the CUBE of i+offset is calculated. If i is 1, which it is the first time through, then we will be looking for the cube of 1+5 = 6, which will result in 216. When using "CUBE", we group the values like this, (1+5)*(1+5)*(1+5) = 6*6*6 = 216. However, when we use WRONG, we group them as 1+5*1+5*1+5 = 1+5+5+5 = Page 44 Chapter 6 - Defines and Macros 16 which is a wrong answer. The parentheses are therefore required to properly group the variables together. It should be clear to you that either "CUBE" or "WRONG" would arrive at a correct answer for a single term replacement such as we did in the last program. The correct values of the cube and the square of the numbers are printed out as well as the wrong values for your inspection. Inspection of line 24 will reveal that we are evaluating "5*(i) + (i)" which is 6 if "i" is one, and in the second case "5*((i) + (i))" which is 10 if "i' is one. The parentheses around the entire expression assure that the value will be evaluated correctly. WHAT IS AN ENUMERATION VARIABLE? Load and display the program named ENUM.C for an example of how to use the "enum" type variable. Line 4 contains the first "enum" type variable named "result" which is a variable which can take on any of the values contained within the parentheses. Actually the variable "result" is an "int" type variable but can be assigned any of the values defined for it. The names within the parentheses are "int" type constants and can be used anywhere it is legal to use an "int" type constant. The constant "win" is assigned the value of 0, "tie" the value 1, "bye" the value 2, etc. In use, the variable "result" is used just like any "int" type variable would be used and can be seen by its use in the program. The "enum" type of variable is intended to be used by you, the programmer, as a coding aid since you can use a constant named "mon" for control structures rather that the meaningless (at least to you) value of 1. Notice that "days" is assigned the values of days of the week in the remainder of the program. If you were to use a "switch" statement, it would be much more meaningful to use the labels "sun", "mon", etc, rather than the more awkward 0, 1, 2, etc. The remainder of the program is simple and will be left to your inspection and understanding. PROGRAMMING EXERCISE 1. Write a program to count from 7 to -5 by counting down. Use #define statements to define the limits. (Hint, you will need to use a decrementing variable in the third part of the "for" loop control. 2. Add some print statements to MACRO.C to see the result of the erroneous addition macro. Page 45