CSc 352: Lecture-16

The Preprocessor

Note: All the programs mentioned in this lecture are in:

/home/cs352/SUMMER02/lecture16progs/

PREPROCESSOR DIRECTIVES

- Preprocessor directives: Lines that begin with #  

- The effect of a directive starts at its place, and continues
  until the end of the file or until it's negated.

- #include
  - We've already seen and used, like:
    #include <stdio.h>
    #include <stdlib.h>
    #include "tree.h"

  - The include line gets replaced by the contents of the given file.
  - If the form is "file.h" then preprocessor first looks at the 
    current directory to find file.h
    If it's like <file.h> then search is done at a system specific 
    directory(such as /usr/include, ...)

  - Typically we can put prototypes of our functions, macro definitions,
    type definitions, etc. in a .h file, and include it in our program.

- #define
  - General form is:
    #define identifier token-string

  - Ex:
    #define PI 3.14159 
    #define TRUE 1
    (The preprocessor replaces every occurence of PI, and TRUE in the 
    rest of the program, except in quoted strings, with the given token 
    string.)
  
  - A long definition can continue the next line by putting \ at the end. 

- Macro definitions
  - General form is:
    #define identifier(identifier, ..., identifier) token-string

  - Ex:
    see macros.c

  - Common mistake: to put ; at the end.(; is interpreted as part of the
    token string then.)

  - Frequently used to replace functions.(more efficient)
    see fmacro.c

  - #undef identifier
    will make the previous definition of a macro forgotten.

  - see useqsort.c (the usage of directives, and functions as arguments
    to functions.

  - Common macros(that are already defined in the libraries):
    - getchar(), putchar() in stdio.h

    - macros operating on characters like isalpha(c), isupper(c), ...
      defined in ctype.h

    - assert(), in the standard header file assert.h
      to ensure the value of an expr is what you expect.
      see assert.c
    

- Conditional Compilation
  - Preprocessor has directives for conditional compilation.

  - Each directive of the general form:
    #if const-int-expr  (in order for cond. comp. expr. must be true)     
    #ifdef  identifier  (identifier must bedefined prev, i.e. in #define)
    #ifndef identifier  (identifier must not be defined previously)
    
    provides cond. compilation until
    #endif

  - Each of the #if directives can also be followed by
    #elif const-int-expr   (for doing else if ....)
    #else                  (for doing else  ....)

    followed by
    #endif

  - Why useful?
    If a big project and want to define constants, need to check if
    define already, if necc.. #undef
    For portability(if writing machine dependent code, might check
    the defined constants and stuff..)
    Debugging, error messages, etc..  
    
  - see moremacro.c