C Preprocessor: More

Conditional Compilation: Rules

Directives

Directive

Meaning

#if

Preprocessor condition (simple arithmetic, at most)

#ifdef

Definedness of a macro (regardless of its value)

#ifndef

Not-definedness of a macro

#else

(no comment)

#elif

as opposed to C’s else if

#endif

(no comment)

Operators for use with* if and elif

Operator

Meaning

defined

Definedness of a macro

!

Boolean NOT

&&

Boolean AND

||

Boolean OR

==

Equal

!=

Unequal

Conditional Compilation: Examples

Commenting out lines

#if 0 /* argh, there's a bug somewhere */
     int i;
     for (i=0; i<2; i--)
         do_something();
#else
     do_something();
     do_something();
#endif

Multiple Conditions Combined

#if defined DEBUG && NUMBER == 3
    fprintf(stderr, "NUMBER equals 3\n");
#endif

Conditional Compilation: Last Words

Conditional compilation …

  • Doesn’t make code more readable

  • Begs for errors

  • Is quite tempting to use in a hurry

Typical uses

  • Same code on multiple OS’s

    • Better to extract OS-specific concepts

    • Define clear separation between OS independent and OS dependent code

    • Avoid inline #ifdef’s (maintenance horror)

  • “Release” and “Debug” versions of the same code base

    • Again: avoid inline #ifdef’s

    • Define macros that expand appropriately

Macros: Spanning Multiple Lines

Macro definition can only span one line ⟶ line continuation

(Extremely Nonsensical) Multiline Macro

#define forever(body) \
    for (;;) { \
        body; \
    }

...
int x = 1;
forever(printf("%d\n", x); ++x;);
...

Macros: Multiple Statements as One Statement (1)

A Block Is Not a Statement

#define do_much() \
    { \
        do_this(); \
        do_that(); \
    }

...
if (42)
    do_much(); /* ERROR! */
else
    do_less();

Macros: Multiple Statements as One Statement (2)

Employ a little trick …

Making A Block Into A Statement

#define do_much() \
    do { \
        do_this(); \
        do_that(); \
    } while (0)

Silence Warnings of Microsoft’s C Implementation

__pragma(warning(push))
__pragma(warning(disable:4127))
...
__pragma(warning(pop))

Stringification (1)

Commmon problem: output a C expression

Macro Usage in Code

...
WARN_IF(i>10);
...

Should yield on stderr

Appearance on stderr

WARNING: i>10

Stringification (2)

Solution: Stringification

#define WARN_IF(expr) \
    do { \
        if (expr) \
            fprintf(stderr, "WARNING: " #expr "\n"); \
    } while (0)

Macro argument is used twice …

  • evaluated as C in the if statemant

  • converted into a C string using #

Token Pasting (1)

Common Problem: construct C identifiers from macro parameters

Redundant Code

struct command
{
    char *name;
    void (*function) (void);
};

struct command commands[] =
{
    { "help", function_help },
    { "quit", function_quit }
};

Token Pasting (2)

Solution: Token Pasting

#define COMMAND(name) { #name, function_ ## name }

struct command commands[] =
{
    COMMAND(help),
    COMMAND(quit)
};

Warnings and Errors

void inject_virus(HANDLE doomed_process)
{
#ifdef WIN32
    void *foreign_mem = VirtualAllocEx(
        doomed_process,
        0,
        8192,
        MEM_COMMIT,
        PAGE_EXECUTE|PAGE_READWRITE);
    ...
#else
#   error cannot infect foreign processes
#endif
}

Predefined Macros (1)

Macro

Meaning

__FILE__

Name of current input file (C string)

__LINE__

Current line current input file (integer)

#define WARN_IF(expr) \
    do { \
        if (expr) \
            fprintf(stderr, "%s:%d: WARNING: " #expr "\n", \
                __FILE__, __LINE__); \
    } while (0)
  • Gives the position where WARN_IF was expanded, not where WARN_IF was defined

The C Preprocessor: Last Words

Always think twice! First thought is likely wrong.

  • Inline preprocessorisms pollute code

  • Code should be kept readable and obvious

  • Push down preprocessorisms into (architecture) specific places

    • Well defined selection macros

    • Forwarding-Headers

    • Common abstractions

Attention

  • Refactor immediately when smell detected!

  • It is like the pest!