preprocessing-file: group module-file
module-file: pp-global-module-fragment pp-module group pp-private-module-fragment
pp-global-module-fragment: module ; new-line group
pp-private-module-fragment: module : private ; new-line group
group: group-part group group-part
group-part: control-line if-section text-line # conditionally-supported-directive
control-line: # include pp-tokens new-line pp-import # define identifier replacement-list new-line # define identifier lparen identifier-list ) replacement-list new-line # define identifier lparen ... ) replacement-list new-line # define identifier lparen identifier-list , ... ) replacement-list new-line # undef identifier new-line # line pp-tokens new-line # error pp-tokens new-line # pragma pp-tokens new-line # new-line
if-section: if-group elif-groups else-group endif-line
if-group: # if constant-expression new-line group # ifdef identifier new-line group # ifndef identifier new-line group
elif-groups: elif-group elif-groups elif-group
elif-group: # elif constant-expression new-line group
else-group: # else new-line group
endif-line: # endif new-line
text-line: pp-tokens new-line
conditionally-supported-directive: pp-tokens new-line
lparen: a ( character not immediately preceded by white-space
identifier-list: identifier identifier-list , identifier
replacement-list: pp-tokens
pp-tokens: preprocessing-token pp-tokens preprocessing-token
new-line: the new-line character
# // preprocessing directive module ; // preprocessing directive export module leftpad; // preprocessing directive import <string>; // preprocessing directive export import "squee"; // preprocessing directive import rightpad; // preprocessing directive import :part; // preprocessing directive module // not a preprocessing directive ; // not a preprocessing directive export // not a preprocessing directive import // not a preprocessing directive foo; // not a preprocessing directive export // not a preprocessing directive import foo; // preprocessing directive (ill-formed at phase 7) import :: // not a preprocessing directive import -> // not a preprocessing directive— end example
defined-macro-expression: defined identifier defined ( identifier )
h-preprocessing-token: any preprocessing-token other than >
h-pp-tokens: h-preprocessing-token h-pp-tokens h-preprocessing-token
header-name-tokens: string-literal < h-pp-tokens >
has-include-expression: __has_include ( header-name ) __has_include ( header-name-tokens )
has-attribute-expression: __has_cpp_attribute ( pp-tokens )
Attribute | Value |
carries_dependency | 200809L |
deprecated | 201309L |
fallthrough | 201603L |
likely | 201803L |
maybe_unused | 201603L |
no_unique_address | 201803L |
nodiscard | 201907L |
noreturn | 200809L |
unlikely | 201803L |
# if constant-expression new-line group # elif constant-expression new-line groupcheck whether the controlling constant expression evaluates to nonzero.
#if 'z' - 'a' == 25 if ('z' - 'a' == 25)
# ifdef identifier new-line group # ifndef identifier new-line groupcheck whether the identifier is or is not currently defined as a macro name.
#if __has_include(<optional>) # include <optional> # if __cpp_lib_optional >= 201603 # define have_optional 1 # endif #elif __has_include(<experimental/optional>) # include <experimental/optional> # if __cpp_lib_experimental_optional >= 201411 # define have_optional 1 # define experimental_optional 1 # endif #endif #ifndef have_optional # define have_optional 0 #endif— end example
#if __has_cpp_attribute(acme::deprecated) # define ATTR_DEPRECATED(msg) [[acme::deprecated(msg)]] #else # define ATTR_DEPRECATED(msg) [[deprecated(msg)]] #endif ATTR_DEPRECATED("This function is deprecated") void anvil();— end example
# include < h-char-sequence > new-linesearches a sequence of implementation-defined places for a header identified uniquely by the specified sequence between the < and > delimiters, and causes the replacement of that directive by the entire contents of the header.
# include " q-char-sequence " new-linecauses the replacement of that directive by the entire contents of the source file identified by the specified sequence between the " delimiters.
# include < h-char-sequence > new-linewith the identical contained sequence (including > characters, if any) from the original directive.
# include pp-tokens new-line(that does not match one of the two previous forms) is permitted.
import header-name ; new-line
#include <stdio.h> #include <unistd.h> #include "usefullib.h" #include "myprog.h"— end note
#if VERSION == 1 #define INCFILE "vers1.h" #elif VERSION == 2 #define INCFILE "vers2.h" // and so on #else #define INCFILE "versN.h" #endif #include INCFILE— end example
pp-module: export module pp-tokens ; new-line
pp-import: export import header-name pp-tokens ; new-line export import header-name-tokens pp-tokens ; new-line export import pp-tokens ; new-line
Importable header "a.h":
#define X 123 // #1 #define Y 45 // #2 #define Z a // #3 #undef X // point of undefinition of #1 in "a.h"
Importable header "b.h":
import "a.h"; // point of definition of #1, #2, and #3, point of undefinition of #1 in "b.h" #define X 456 // OK, #1 is not active #define Y 6 // error: #2 is active
Importable header "c.h":
#define Y 45 // #4 #define Z c // #5
Importable header "d.h":
import "a.h"; // point of definition of #1, #2, and #3, point of undefinition of #1 in "d.h" import "c.h"; // point of definition of #4 and #5 in "d.h" int a = Y; // OK, active macro definitions #2 and #4 are valid redefinitions int c = Z; // error: active macro definitions #3 and #5 are not valid redefinitions of Z— end example
#define OBJ_LIKE (1-1) #define OBJ_LIKE /* white space */ (1-1) /* other */ #define FUNC_LIKE(a) ( a ) #define FUNC_LIKE( a )( /* note the white space */ \ a /* other stuff on this line */ )
#define OBJ_LIKE (0) // different token sequence #define OBJ_LIKE (1 - 1) // different white space #define FUNC_LIKE(b) ( a ) // different parameter usage #define FUNC_LIKE(b) ( b ) // different parameter spelling
# define identifier replacement-list new-linedefines an object-like macro that causes each subsequent instance of the macro name145 to be replaced by the replacement list of preprocessing tokens that constitute the remainder of the directive.146
#define TABSIZE 100 int table[TABSIZE];
# define identifier lparen identifier-list ) replacement-list new-line # define identifier lparen ... ) replacement-list new-line # define identifier lparen identifier-list , ... ) replacement-list new-linedefines a function-like macro with parameters, whose use is similar syntactically to a function call.
#define max(a, b) ((a) > (b) ? (a) : (b))
va-opt-replacement: __VA_OPT__ ( pp-tokens )
#define LPAREN() ( #define G(Q) 42 #define F(R, X, ...) __VA_OPT__(G R X) ) int x = F(LPAREN(), 0, <:-); // replaced by int x = 42;— end example
#define debug(...) fprintf(stderr, __VA_ARGS__) #define showlist(...) puts(#__VA_ARGS__) #define report(test, ...) ((test) ? puts(#test) : printf(__VA_ARGS__)) debug("Flag"); debug("X = %d\n", x); showlist(The first, second, and third items.); report(x>y, "x is %d but y is %d", x, y);results in
fprintf(stderr, "Flag"); fprintf(stderr, "X = %d\n", x); puts("The first, second, and third items."); ((x>y) ? puts("x>y") : printf("x is %d but y is %d", x, y));
#define F(...) f(0 __VA_OPT__(,) __VA_ARGS__) #define G(X, ...) f(0, X __VA_OPT__(,) __VA_ARGS__) #define SDEF(sname, ...) S sname __VA_OPT__(= { __VA_ARGS__ }) #define EMP F(a, b, c) // replaced by f(0, a, b, c) F() // replaced by f(0) F(EMP) // replaced by f(0) G(a, b, c) // replaced by f(0, a, b, c) G(a, ) // replaced by f(0, a) G(a) // replaced by f(0, a) SDEF(foo); // replaced by S foo; SDEF(bar, 1, 2); // replaced by S bar = { 1, 2 }; #define H1(X, ...) X __VA_OPT__(##) __VA_ARGS__ // error: ## may not appear at // the beginning of a replacement list ([cpp.concat]) #define H2(X, Y, ...) __VA_OPT__(X ## Y,) __VA_ARGS__ H2(a, b, c, d) // replaced by ab, c, d #define H3(X, ...) #__VA_OPT__(X##X X##X) H3(, 0) // replaced by "" #define H4(X, ...) __VA_OPT__(a X ## X) ## b H4(, 1) // replaced by a b #define H5A(...) __VA_OPT__()/**/__VA_OPT__() #define H5B(X) a ## X ## b #define H5C(X) H5B(X) H5C(H5A()) // replaced by ab— end example
#define str(s) # s #define xstr(s) str(s) #define debug(s, t) printf("x" # s "= %d, x" # t "= %s", \ x ## s, x ## t) #define INCFILE(n) vers ## n #define glue(a, b) a ## b #define xglue(a, b) glue(a, b) #define HIGHLOW "hello" #define LOW LOW ", world" debug(1, 2); fputs(str(strncmp("abc\0d", "abc", '\4') // this goes away == 0) str(: @\n), s); #include xstr(INCFILE(2).h) glue(HIGH, LOW); xglue(HIGH, LOW)results in
printf("x" "1" "= %d, x" "2" "= %s", x1, x2); fputs("strncmp(\"abc\\0d\", \"abc\", '\\4') == 0" ": @\n", s); #include "vers2.h" (after macro replacement, before file access) "hello"; "hello" ", world"or, after concatenation of the character string literals,
printf("x1= %d, x2= %s", x1, x2); fputs("strncmp(\"abc\\0d\", \"abc\", '\\4') == 0: @\n", s); #include "vers2.h" (after macro replacement, before file access) "hello"; "hello, world"
#define hash_hash # ## # #define mkstr(a) # a #define in_between(a) mkstr(a) #define join(c, d) in_between(c hash_hash d) char p[] = join(x, y); // equivalent to char p[] = "x ## y";
join(x, y) in_between(x hash_hash y) in_between(x ## y) mkstr(x ## y) "x ## y"
#define t(x,y,z) x ## y ## z int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,), t(10,,), t(,11,), t(,,12), t(,,) };results in
int j[] = { 123, 45, 67, 89, 10, 11, 12, };
#define x 3 #define f(a) f(x * (a)) #undef x #define x 2 #define g f #define z z[0] #define h g(~ #define m(a) a(w) #define w 0,1 #define t(a) a #define p() int #define q(x) x #define r(x,y) x ## y #define str(x) # x f(y+1) + f(f(z)) % t(t(g)(0) + t)(1); g(x+(3,4)-w) | h 5) & m (f)^m(m); p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) }; char c[2][6] = { str(hello), str() };results in
f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1); f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1); int i[] = { 1, 23, 4, 5, }; char c[2][6] = { "hello", "" };
# line digit-sequence new-linecauses the implementation to behave as if the following sequence of source lines begins with a source line that has a line number as specified by the digit sequence (interpreted as a decimal integer).
# line digit-sequence " s-char-sequence " new-linesets the presumed line number similarly and changes the presumed name of the source file to be the contents of the character string literal.
# line pp-tokens new-line(that does not match one of the two previous forms) is permitted.
# pragma pp-tokens new-linecauses the implementation to behave in an implementation-defined manner.
Macro name | Value |
201603L | |
201304L | |
201902L | |
200704L | |
201606L | |
200809L | |
201304L | |
201603L | |
201811L | |
201907L | |
201806L | |
201907L | |
201907L | |
201711L | |
201811L | |
201907L | |
200707L | |
201304L | |
201907L | |
200604L | |
201707L | |
201411L | |
201603L | |
201707L | |
201606L | |
201603L | |
201606L | |
201902L | |
201806L | |
201907L | |
201511L | |
201803L | |
200806L | |
201606L | |
200907L | |
201907L | |
201411L | |
201510L | |
201911L | |
201606L | |
200809L | |
201603L | |
200710L | |
200710L | |
201304L | |
200610L | |
201309L | |
201411L | |
201606L | |
201611L | |
200806L | |
200704L | |
200710L | |
200809L | |
201907L | |
201304L | |
200704L | |
201611L |
_Pragma ( string-literal )is processed as follows: The string-literal is destringized by deleting the L prefix, if present, deleting the leading and trailing double-quotes, replacing each escape sequence \" by a double-quote, and replacing each escape sequence \\ by a single backslash.
#pragma listing on "..\listing.dir"can also be expressed as:
_Pragma ( "listing on \"..\\listing.dir\"" )
#define LISTING(x) PRAGMA(listing on #x) #define PRAGMA(x) _Pragma(#x) LISTING( ..\listing.dir )