The Preprocessor#

(Chapter 8)

               +-----------+               +---------+               +--------+
   -------->   | hello.c   |   -------->   | hello.o |   -------->   | hello  |
     edit      +-----------+    compile    +---------+    Linking    +--------+

                Keywords       Preprocessor         
                Identifiers    Lexical analysis     
                Constants      Syntax analysis      
                Operators      Semantic analysis    
                Punctuation    

Basic Commands#

#include <stdio.h>

#include “myfile.h”

---------------------------------

#define   identifier    string

#undef   identifier

#define#

#define PI    3.14159
#define C2    99792.458 /*the speed of light*/

#define EOF   (-1)
#define MAXINT 2147483647

#define EQ ==

#define do  /* blank */

while (i EQ 1) do {
    ......

Macros#


#define SQ(x) ((x) * (x))

SQ(7 + w)    /*expands to */    ((7 + w) * (7 + w))

SQ(SQ(*p))    /*expands to */    ((((*p) * (*p))) * (((*p) * (*p))))


#define SQ(x) x * x

SQ(a + b)    /*expands to */    a + b * a + b
#define SQ(x) (x) * (x)

4 / SQ (2)    /*expands to */    4 / (2) * (2)
#define SQ (x) ((x) * (x))

SQ(7)    /*expands to */    (x) ((x) * (x)) (7)
#define   SQ(x)   ((x) * (x)); /*Be careful!!!*/

/*because*/
if (x == 2)
   x = SQ(y);
else
   ++x;

Nested Macros#

#define min(x, y) (((x) < (y)) ? (x) : (y))

m = min(u, v)    /*expands to */    m = (((u) < (v)) ? (u) : (v))

#define   min4(a, b, c, d)   min(min(a,b), min(c,d))

You can stop the compiler after the preprocessing step and view the code:

gcc -E tmp.c
# @title
%%writefile tmp.c
#include <stdio.h>
#define SQUARE(x) ((x) * (x))

int main() {
    printf("%d\n", SQUARE(5));
    return 0;
}
  Cell In[1], line 6
    int main() {
        ^
SyntaxError: invalid syntax
# @title
!gcc tmp.c -o tmp
!./tmp

More about Macros#

Macros are not functions Even when written with all the parentheses

#define MAX(a, b) (((a) > (b)) ? (a) : (b))
int a[4] = {0};
int biggest = 0;

biggest = x[0];
i = 1;
while (i < 4)
    biggest = MAX(biggest, x[i++]);

This code would have worked fine if MAX was a function !

Expands to:

biggest = (((biggest) > (x[i++])) ? (biggest) : (x[i++]));

i is incremented twice when the condition (biggest > x[i++]) is false, and only once when it is true.

Conditional Compilation#

#if constant_integral_expression
#ifdef  identifier
#ifndef identifier

#endif

Conditional Compilation (example 1)#

#if defined ( HP9000 ) || defined ( SUN4 ) && !defined( VAX )

/*Machine-dependent code*/


#endif

Conditional Compilation (example 2)#

#define DEBUG

#ifdef DEBUG

printf( debug: a = %d\n, a );

#endif

Conditional Compilation (example 3)#

#ifndef __HEADER_H
#define __HEADER_H
.
.
.
#endif

Conditional Compilation#

statement
#if 0

more statements
#endif

and still more statements

------------------------------------------

#elif constant_interal_expression

#else

#endif

Predefined Macros#

Four predefined macros (can’t be undefined) :

__DATE__	A string containing the current date
__FILE__	A string containing the file name
__LINE__	An integer representing the current line number
__TIME__	A string containing the current time


Header Files#

What are Header Files?#

Header files (.h files) contain declarations of functions, macros, constants, and structures. They allow for code reuse and modularity by separating the interface (declarations) from the implementation (definitions).

Key Points:#

  • Function Prototypes: Declare functions that will be defined in other source files.

  • Macros and Constants: Define reusable code snippets or constants.

  • Include Guard: Prevents multiple inclusions of the same header file.

Example: Header File (math_functions.h)#

#ifndef MATH_FUNCTIONS_H  // Include guard to prevent multiple inclusions
#define MATH_FUNCTIONS_H

// Function prototypes
int add(int a, int b);
int subtract(int a, int b);

#endif // MATH_FUNCTIONS_H

Conditional Compilation in C#

What is Conditional Compilation?#

Conditional compilation allows for compiling code conditionally based on certain preprocessor directives like #define, #ifdef, #ifndef, and #endif. It is useful for including or excluding code depending on different conditions (e.g., platform-specific code, debugging).

Key Points:#

  • #define: Defines a constant or flag for conditional checks.

  • #ifdef / #ifndef: Checks if a macro is defined or not.

  • #endif: Ends a conditional block.

Example: Conditional Compilation with Debug Flag#

We will modify the program to conditionally include a debug message.

1. Header File (math_functions.h)#

#ifndef MATH_FUNCTIONS_H
#define MATH_FUNCTIONS_H

// Function prototypes
int add(int a, int b);
int subtract(int a, int b);

#endif // MATH_FUNCTIONS_H

// Conditionally include debugging
#define DEBUG   // Comment this line to disable debug messages

2. Implementation File (math_functions.c)#

#include "math_functions.h"
#include <stdio.h>

// Function definitions
int add(int a, int b) {
    return a + b;
}

int subtract(int a, int b) {
    return a - b;
}

3. Main File (main.c)#

#include <stdio.h>
#include "math_functions.h"


int main() {
    int sum = add(5, 3);
    int difference = subtract(5, 3);

    // Conditional Debug Output
    #ifdef DEBUG
    printf("Debug: Sum is %d\n", sum);
    #endif

    printf("Sum: %d\n", sum);
    printf("Difference: %d\n", difference);

    return 0;
}

Explanation:#

  • #define DEBUG: This flag enables the debug message.

  • #ifdef DEBUG: If DEBUG is defined, the debug message will be included in the compilation.

  • No DEBUG flag: If you comment out #define DEBUG, the debug message will be excluded from the compilation.


Compilation Steps#

To compile and link the program:

  1. Compile and link everything in one command:

    gcc main.c math_functions.c -o program
    
  2. Run the program:

    ./program
    

Assert#

#include <stdio.h>
#include <stdlib.h>

#if defined(NDEBUG)
#define assert(ignore) ((void)0) /* ignore it */
#else
#define assert(expr)                            \
    do                                          \
    {                                           \
        if (!(expr))                            \
        {                                       \
            printf("\n%s %s\n%s %s\n%s %d\n\n", \
                   "Assertion failed:", #expr,  \
                   "In file:", __FILE__,        \
                   "At line:", __LINE__);       \
            abort();                            \
        }                                       \
    } while (0)
#endif