Preprocessor#
Let’s recap what we have learned so far about the C preprocessor:
It is a preliminary compilation step, happening before the compilation proper (phase 7)
Its input is a stream of tokens
What that means, is that the preprocessor manipulates text, not values:
It cannot use the result of expressions like
1 + 3,sizeof(int), orstrlen("Hello")[1] that are evaluated during phase 7.What it can do is more akin to string manipulation than math: it is meant to modify / generate code, not to do computation
Interacting with the preprocessor is done by starting a line with the # character, followed by a preprocessing directive. (Any number of spaces can be present before and after the # character)
Directives#
File inclusion#
#include <filename>Look for a file called filename in folders provided to the preprocessor[2] with the
-Iflag, and in standard folders configured at compiler installation. Once the file is found, its content is pasted verbatim in place of the#includeline
#include "filename"Same as above, but look into the current directory first
Source : cppreference
Note
No assumption is made about the content of the included file, it technically doesn’t have to be valid C, or even code at all…
Macros#
Object-like#
#defineidentifier replacementAfter this line, anytime identifier appears in the source code, it will be replaced by replacement
#defineidentifierEquivalent to
#define identifier 1
Function-like#
#defineidentifier(parameters)replacementAfter this line, anytime identifier(values) appears in the source code, it will be replaced by replacement, replacing any occurence of a parameter by the value provided by the caller.
#defineidentifier(parameters, ...)replacementSimilar to the previous definition, but zero or more extra parameters can be supplied. The identifier
__VA_ARGS__will be replaced by those extra parameters. Additionally,__VA_OPT__(x)will be replaced by nothing if zero extra parameters were supplied, or byxif at least one extra parameter was supplied.
Source: cppreference
Conditional inclusion#
#ifcondition A#elseB#endifEvaluates condition (so at preprocessor-time), then replaces the whole
#if…#endifblock with A or B depending on the result.#ifdefMACROEquivalent to
#if defined(MACRO)#ifndefMACROEquivalent to
#if !defined(MACRO)#elifcondition2 B#endifConvenient way to chain multiple conditions without nesting, equivalent to:
#else # if condition2 B # endif #endif
#elifdefMACROAdded in C23 for constistency, equivalent to
#elif defined(MACRO)#elifndefMACROAdded in C23 for constistency, equivalent to
#elif !defined(MACRO)
Source: cppreference
The operators#
We have seen previously that the input of the preprocessor is a stream of tokens, each with a type.
It should be of no surprise then, that the 2 preprocessor operators are about manipulating tokens.
#Set token type to string literal
name name
##Concatenate 2 tokens
some thing something
Those operators can only be used on parameters of function-like macros.
Source: cppreference