
Some lines in a C program are not C. They begin with #, and they are instructions to the compiler about the text it is reading: use this name for this value, read this file here, show me what you are compiling. Every program in the course has had two of them. This section is the rest, and it is short, because this compiler's preprocessor is small: what it has is #define and #include, and the point of the section is as much what it will not do as what it will.
#define#define WIDTH 40
#define HEIGHT 24
From that line on, wherever the compiler meets the word WIDTH it reads 40 instead. That is all a #define is: a name and the text it stands for, substituted before the C is looked at. There is no = and no ;, because it is not a statement.
Why bother, when you could write 40? Because the court is forty wide in twenty places, and when it becomes thirty-eight you want to change one line. And because WIDTH says what the 40 is. Names in capitals are the convention, so that a reader knows at once that WIDTH is a #define and not a variable. S15 gave another reason: sizeof will not take an array here, so the size lives in a #define and both the declaration and the loops use it.
A #define may stand for anything, and may use earlier ones:
#define AREA WIDTH * HEIGHT
#define WALL '#'
AREA is 40 * 24, 960. And STDIO.H is nothing but a list of these: TRUE is 1, FALSE is 0, EOF is -1, NULL is 0, and void is int - which is why void works only when STDIO.H is at the top (S13).
Because a #define substitutes text, not a value, it can surprise you in two ways.
The text goes in as written, brackets or none. #define HALF 40 / 2 then 100 - HALF is 100 - 40 / 2, which is 80 - as it happens what you meant, because / binds before -. Write HALF * 3 and you get 40 / 2 * 3, 60, also right; but #define NEXT 40 + 1 then NEXT * 2 is 40 + 1 * 2, 42, not 82. When a #define is an expression, put brackets round it in the #define: #define NEXT (40 + 1).
Everything to the end of the line is the text - including a semicolon you did not mean. This one comes with its own error message from another part of the file:
#define HELLO "hello";
printf(HELLO);
ERROR 0 AT LINE 8 ... missing ')' - at the printf line, which looks perfect. The compiler saw printf("hello";);. When an error is reported at a line that uses a #define, and the line is right, look at the #define.
If you know the preprocessor from anywhere else, three things are missing, and the compiler says so in the same words each time.
#define SQ(x) x * x is ERROR 6 ... RESTRICTION: macros may not have parameters. Where you would have written a macro with arguments, write a function (S13).#if, #ifdef, #ifndef, #else and #endif do not exist: any of them, anywhere in the file, is ERROR 3 ... not a preprocessor command. Nor does #undef. A name, once defined, stands for its text to the end of the file.#list, below, and #data, #translate, #error and #direct, which this course does not need.#includeThree spellings, all the same here: #include STDIO.H, #include "STDIO.H" and #include <STDIO.H>. The file is read at that point as if its lines were in yours. The course writes the first, which is the manual's, and reserves the question marks for the fourth form, #include ?STDIO.LIB?, which S8 explained: not "read this file" but "search this file for the functions I have called and compile those".
A file you write yourself may be included the same way. When Breakout's #defines outgrow the top of the file they will go in BREAKOUT.H, and each stage will #include BREAKOUT.H.
#listPut #list+ on the command line before the file name and the compiler prints every line as it reads it: HC #list+ NAME.C. #list- turns it off again, and STDIO.H has one at its top so that its own lines go by unseen. S6 showed the effect; the use of it is in S23, where the library is read as a program.
#include STDIO.H
#define WIDTH 40
#define HEIGHT 24
#define AREA WIDTH * HEIGHT
#define WALL '#'
main()
{
printf("%d by %d is %d\n", WIDTH, HEIGHT, AREA);
printf("%c\n", WALL);
printf("%d %d %d\n", TRUE, FALSE, EOF);
}
#include ?STDIO.LIB?
Starting from
Typed as PRE.C; compiled and run.
What you should see
40 by 24 is 960
#
1 0 -1
#define AREA WIDTH * HEIGHT to #define AREA WIDTH + HEIGHT and print AREA * 2. Work out what the compiler saw, then run it.; at the end of #define WALL '#'. Where is the error reported?#ifdef WALL before the second printf and #endif after it. What does the compiler say?19.1 Define ROWS and COLS, declare char grid[ROWS][COLS], fill it with . in two loops that use the same names, and print it.
19.2 Define SQUARE(x) as x * x and try to use it. Then write the function that replaces it.
19.3 Put #define GREETING "Hello, Einstein" in a file MY.H, #include MY.H from a program, and print GREETING.
Worked solutions are in Appendix II.
| Symptom | Cause |
|---|---|
missing ')' or a similar error on a line that looks right | The line uses a #define that ends in ;. |
RESTRICTION: macros may not have parameters | #define NAME(x). Write a function. |
not a preprocessor command | #if, #ifdef, #ifndef, #else, #endif or #undef. None exists here. |
An expression using a #define gives the wrong answer | The #define's text was substituted without brackets. Bracket it in the #define. |
undefined symbol for a name in capitals | The #define is below its first use, or misspelt. |
#define NAME text substitutes text, to the end of the line, no ;, brackets round expressions. No arguments, no #if of any kind, no #undef. #include FILE, "FILE" or <FILE> reads a file in; ?FILE? searches a library. #list+ on the command line shows every line compiled.
S20, Files - writing to the disc and reading back: a high-score table for the game, and the two things this library does to a text file that you need to know about.