Files
2025-10-25 03:02:53 +03:00

104 lines
4.7 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[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.2Universal character names[lex.universal.char]") ([[lex.charset]](lex.charset "5.3.1Character 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)