Ch3.14: stringify

Macros and Token Manipulation

The C++ preprocessor provides two special operators that manipulate tokens:

These operators work only inside #define macros. They are powerful but must be used carefully.

Stringification: #

The # operator converts a macro argument into a string literal.


#define STR(x) #x

println(STR(hello world));

Output:


hello world

The argument is not evaluated — it is turned into text exactly as written.

Example: printing expressions


#define SHOW(expr) println(#expr, " = ", (expr))

SHOW(2 + 3);
SHOW(10 * 20);

Output:


2 + 3 = 5
10 * 20 = 200

Token Pasting: ##

The ## operator concatenates two tokens into one.


#define MAKE_NAME(prefix, id) prefix##id

int MAKE_NAME(var, 1) = 42;   // becomes: int var1 = 42;

Token pasting is often used to generate variable names or function names.

Example: generating enum-to-string helpers


#define CASE_TO_STRING(x) case x: return #x;

    switch (c) {
        CASE_TO_STRING(red)
        CASE_TO_STRING(green)
        CASE_TO_STRING(blue)
    }

Combining # and ##

You can combine both operators to build more complex macros.


#define MAKE_GETTER(name) \
    int get_##name() { \
        println("getting " #name); \
        return name; \
    }

int value = 123;
MAKE_GETTER(value)

Expands to:


int get_value() {
    println("getting " "value");
    return value;
}

Macro Pitfalls

1. No type checking

Macros operate on text, not types. Errors may appear only after expansion.

2. Side effects

Macros may evaluate arguments multiple times.


#define SQR(x) ((x) * (x))

SQR(++i);   // expands to ((++i) * (++i))

This increments i twice — almost never intended.

3. Hard to debug

Debuggers show expanded code, not macro definitions.

4. Token pasting can create invalid code


#define BAD(x) x##123abc   // invalid token

The compiler will error after expansion.

Safe Usage Patterns

Macros are powerful but should be used sparingly.

Key takeaways