Preprocessor features

Macro string replacement

The following macro definition associates the text “1 / 12” with the token “VALUE”:

#define VALUE 1 / 12

A function-like macro supports parameters; although the parameter list can be empty. The following macro definition associates the expression “(A + B)” with the token “ADD” that has parameters “A” and “B”.

#define ADD(A, B) (A + B)

A function-like macro declaration cannot have whitespace between the token and the first, opening parenthesis. If whitespace is present, the macro is interpreted as object-like with everything starting at the first parenthesis included in the replacement text.

Expansion

The preprocessor replaces each token of the code that matches a macro token with the associated replacement text in what is known as macro expansion. Note that text of string literals and comments is not parsed as tokens and is therefore ignored for macro expansion. For a function-like macro, the macro parameters are also replaced with the values specified in the macro reference. For example, ADD(VALUE, 2) expands to 1 / 12 + 2.

Token stringification

The stringification operator (a.k.a. stringizing operator), denoted by # converts a token into a string literal, escaping any quotes or backslashes as needed. For definition:

#define str(s) #s

str(\n) expands to “\n” and str(p = “foo\n”;) expands to “p = “foo\n”;“.

If stringification of the expansion of a macro argument is desired, two levels of macros must be used. For definition:

#define xstr(s) str(s)
#define str(s) #s
#define foo 4

str(foo) expands to “foo” and xstr(foo) expands to “4”.

Token concatenation

The token pasting operator, denoted by ##, concatenates two tokens into one. For definition:

#define DECLARE_STRUCT_TYPE(name) typedef struct name##_s name##_t

DECLARE_STRUCT_TYPE(g_object) expands to typedef struct g_object_s g_object_t.

Abort

Processing can be aborted via the #error directive. For example:

#if RUBY_VERSION == 190
#error Ruby version 1.9.0 is not supported
#endif

Binary resource inclusion

C23 and C++26 introduce the #embed directive for binary resource inclusion which allows including the content of a binary file into a source even though it’s not valid C code.

const unsigned char icon_display_data[] = {
    #embed "art.png"
};

/* specify any type which can be initialized form integer constant expressions will do */
const char reset_blob[] = {
    #embed "data.bin"
};

/* attributes work just as well */
const signed char aligned_data_str[] __attribute__ ((aligned (8))) = {
    #embed "attributes.xml"
};

int main() {
    return
#embed </dev/urandom> limit(1)
    ;
}
#define max(a,b) (((a) > (b)) ? (a) : (b))

Hidden order of operation

Failure to bracket arguments can lead to unexpected results. For example, a macro to double a value might be written as:

#define double(x) 2 * x

But double(1 + 2) expands to 2 * 1 + 2 which due to order of operations, evaluates to 4 when the expected is 6. To mitigate this problem, a macro should bracket all expressions and substitution variables:

#define double(x) (2 * (x))