.NH Scope Rules: Who Knows About What .PP A complete C program need not be compiled all at once; the source text of the program may be kept in several files, and previously compiled routines may be loaded from libraries. How do we arrange that data gets passed from one routine to another? We have already seen how to use function arguments and values, so let us talk about external data. Warning: the words .ul declaration and .ul definition are used precisely in this section; don't treat them as the same thing. .PP A major shortcut exists for making .UL extern declarations. If the definition of a variable appears .ul before its use in some function, no .UL extern declaration is needed within the function. Thus, if a file contains .E1 f1( ) { \*.\*.\*. } .SP int foo; .SP f2( ) { \*.\*.\*. foo = 1; \*.\*.\*. } .SP f3( ) { \*.\*.\*. if ( foo ) \*.\*.\*. } .E2 no declaration of .UL foo is needed in either .UL f2 or or .UL f3, because the external definition of .UL foo appears before them. But if .UL f1 wants to use .UL foo, it has to contain the declaration .E1 f1( ) { extern int foo; \*.\*.\*. } .E2 .PP This is true also of any function that exists on another file _ if it wants .UL foo it has to use an .UL extern declaration for it. (If somewhere there is an .UL extern declaration for something, there must also eventually be an external definition of it, or you'll get an ``undefined symbol'' message.) .PP There are some hidden pitfalls in external declarations and definitions if you use multiple source files. To avoid them, first, define and initialize each external variable only once in the entire set of files: .E1 int foo 0; .E2 You can get away with multiple external definitions on .UC UNIX, but not on .UC GCOS, so don't ask for trouble. Multiple initializations are illegal everywhere. Second, at the beginning of any file that contains functions needing a variable whose definition is in some other file, put in an .UL extern declaration, outside of any function: .E1 extern int foo; .SP f1( ) { \*.\*.\*. } etc\*. .E2 .PP The .UL #include compiler control line, to be discussed shortly, lets you make a single copy of the external declarations for a program and then stick them into each of the source files making up the program. .NH #define, #include .PP C provides a very limited macro facility. You can say .E1 #define name something .E2 and thereafter anywhere ``name'' appears as a token, ``something'' will be substituted. This is particularly useful in parametering the sizes of arrays: .E1 #define ARRAYSIZE 100 int arr[ARRAYSIZE]; \*.\*.\*. while( i\*+ < ARRAYSIZE )\*.\*.\*. .E2 (now we can alter the entire program by changing only the .UL define) or in setting up mysterious constants: .E1 #define SET 01 #define INTERRUPT 02 /\** interrupt bit \**/ #define ENABLED 04 \*.\*.\*. if( x & (SET | INTERRUPT | ENABLED) ) \*.\*.\*. .E2 Now we have meaningful words instead of mysterious constants. (The mysterious operators `&' (AND) and `\(or' (OR) will be covered in the next section.) It's an excellent practice to write programs without any literal constants except in .UL #define statements. .PP There are several warnings about .UL #define\*. First, there's no semicolon at the end of a .UL #define; all the text from the name to the end of the line (except for comments) is taken to be the ``something''. When it's put into the text, blanks are placed around it. Good style typically makes the name in the .UL #define upper case _ this makes parameters more visible. Definitions affect things only after they occur, and only within the file in which they occur. Defines can't be nested. Last, if there is a .UL #define in a file, then the first character of the file .ul must be a `#', to signal the preprocessor that definitions exist. .WS .PP The other control word known to C is .UL #include\*. To include one file in your source at compilation time, say .E1 #include "filename" .E2 This is useful for putting a lot of heavily used data definitions and .UL #define statements at the beginning of a file to be compiled. As with .UL #define, the first line of a file containing a .UL #include has to begin with a `#'. And .UL #include can't be nested _ an included file can't contain another .UL #include\*.