104 lines
4.7 KiB
Markdown
104 lines
4.7 KiB
Markdown
[cpp.concat]
|
||
|
||
# 15 Preprocessing directives [[cpp]](./#cpp)
|
||
|
||
## 15.7 Macro replacement [[cpp.replace]](cpp.replace#cpp.concat)
|
||
|
||
### 15.7.4 The ## operator [cpp.concat]
|
||
|
||
[1](#1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L1847)
|
||
|
||
A## preprocessing token shall not occur at the beginning or
|
||
at the end of a replacement list for either form
|
||
of macro definition[.](#1.sentence-1)
|
||
|
||
[2](#2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L1854)
|
||
|
||
If, in the replacement list of a function-like macro, a parameter is
|
||
immediately preceded or followed by a## preprocessing token, the parameter is replaced by the
|
||
corresponding argument's preprocessing token sequence; however, if an argument consists of no preprocessing tokens, the parameter is
|
||
replaced by a placemarker preprocessing token instead[.](#2.sentence-1)[128](#footnote-128 "Placemarker preprocessing tokens do not appear in the syntax because they are temporary entities that exist only within translation phase 4.")
|
||
|
||
[3](#3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L1866)
|
||
|
||
For both object-like and function-like macro invocations, before the
|
||
replacement list is reexamined for more macro names to replace,
|
||
each instance of a## preprocessing token in the replacement list
|
||
(not from an argument) is deleted and the
|
||
preceding preprocessing token is concatenated
|
||
with the following preprocessing token[.](#3.sentence-1)
|
||
|
||
Placemarker preprocessing tokens are handled specially: concatenation
|
||
of two placemarkers results in a single placemarker preprocessing token, and
|
||
concatenation of a placemarker with a non-placemarker preprocessing token results
|
||
in the non-placemarker preprocessing token[.](#3.sentence-2)
|
||
|
||
[*Note [1](#note-1)*:
|
||
|
||
Concatenation can form
|
||
a [*universal-character-name*](lex.universal.char#nt:universal-character-name "5.3.2 Universal character names [lex.universal.char]") ([[lex.charset]](lex.charset "5.3.1 Character sets"))[.](#3.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
If the result is not a valid preprocessing token,
|
||
the program is ill-formed[.](#3.sentence-4)
|
||
|
||
The resulting preprocessing token is available for further macro replacement[.](#3.sentence-5)
|
||
|
||
The order of evaluation of## operators is unspecified[.](#3.sentence-6)
|
||
|
||
[4](#4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L1890)
|
||
|
||
[*Example [1](#example-1)*:
|
||
|
||
The sequence#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 inprintf("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"
|
||
|
||
Space around the # and ## preprocessing tokens in the macro definition
|
||
is optional[.](#4.sentence-2)
|
||
|
||
â *end example*]
|
||
|
||
[5](#5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L1932)
|
||
|
||
[*Example [2](#example-2)*:
|
||
|
||
In the following fragment:#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";
|
||
|
||
The expansion produces, at various stages:join(x, y) in_between(x hash_hash y) in_between(x ## y) mkstr(x ## y)"x ## y"
|
||
|
||
In other words, expanding hash_hash produces a new preprocessing token,
|
||
consisting of two adjacent sharp signs, but this new preprocessing token is not the## operator[.](#5.sentence-3)
|
||
|
||
â *end example*]
|
||
|
||
[6](#6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L1957)
|
||
|
||
[*Example [3](#example-3)*:
|
||
|
||
To illustrate the rules for placemarker preprocessing tokens, the sequence#define t(x,y,z) x ## y ## zint j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,),
|
||
t(10,,), t(,11,), t(,,12), t(,,) }; results inint j[] = { 123, 45, 67, 89, 10, 11, 12, };
|
||
|
||
â *end example*]
|
||
|
||
[128)](#footnote-128)[128)](#footnoteref-128)
|
||
|
||
Placemarker preprocessing tokens do not appear in the syntax
|
||
because they are temporary entities that exist only within translation phase 4[.](#footnote-128.sentence-1)
|