354 lines
18 KiB
Markdown
354 lines
18 KiB
Markdown
[cpp.embed]
|
||
|
||
# 15 Preprocessing directives [[cpp]](./#cpp)
|
||
|
||
## 15.4 Resource inclusion [cpp.embed]
|
||
|
||
### [15.4.1](#gen) General [[cpp.embed.gen]](cpp.embed.gen)
|
||
|
||
[1](#gen-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L845)
|
||
|
||
A [*bracket resource search*](#def:search,bracket_resource "15.4.1 General [cpp.embed.gen]") for a sequence of characters
|
||
searches a sequence of places for a resource identified uniquely
|
||
by that sequence of characters[.](#gen-1.sentence-1)
|
||
|
||
How the places are determined or the resource identified
|
||
is implementation-defined[.](#gen-1.sentence-2)
|
||
|
||
[2](#gen-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L852)
|
||
|
||
A [*quote resource search*](#def:search,quote_resource "15.4.1 General [cpp.embed.gen]") for a sequence of characters
|
||
attempts to identify a resource that is named by the sequence of characters[.](#gen-2.sentence-1)
|
||
|
||
The named resource is searched for
|
||
in an implementation-defined manner[.](#gen-2.sentence-2)
|
||
|
||
If the implementation does not support a quote resource search
|
||
for that sequence of characters, or if the search fails,
|
||
the result of the quote resource search
|
||
is the result of a bracket resource search for the same sequence of characters[.](#gen-2.sentence-3)
|
||
|
||
[3](#gen-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L862)
|
||
|
||
A preprocessing directive of the form
|
||
|
||
# embed [*header-name*](lex.header#nt:header-name "5.6 Header names [lex.header]") [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1 Preamble [cpp.pre]")opt [*new-line*](cpp.pre#nt:new-line "15.1 Preamble [cpp.pre]")
|
||
|
||
causes the replacement of that directive
|
||
by preprocessing tokens derived from data
|
||
in the resource identified by [*header-name*](lex.header#nt:header-name "5.6 Header names [lex.header]"),
|
||
as specified below[.](#gen-3.sentence-1)
|
||
|
||
[4](#gen-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L872)
|
||
|
||
If the [*header-name*](lex.header#nt:header-name "5.6 Header names [lex.header]") is of the form
|
||
|
||
< [*h-char-sequence*](lex.header#nt:h-char-sequence "5.6 Header names [lex.header]") >
|
||
|
||
the resource is identified by a bracket resource search
|
||
for the sequence of characters of the [*h-char-sequence*](lex.header#nt:h-char-sequence "5.6 Header names [lex.header]")[.](#gen-4.sentence-1)
|
||
|
||
[5](#gen-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L880)
|
||
|
||
If the [*header-name*](lex.header#nt:header-name "5.6 Header names [lex.header]") is of the form
|
||
|
||
" [*q-char-sequence*](lex.header#nt:q-char-sequence "5.6 Header names [lex.header]") "
|
||
|
||
the resource is identified by a quote resource search
|
||
for the sequence of characters of the [*q-char-sequence*](lex.header#nt:q-char-sequence "5.6 Header names [lex.header]")[.](#gen-5.sentence-1)
|
||
|
||
[6](#gen-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L888)
|
||
|
||
If a bracket resource search fails,
|
||
or if a quote or bracket resource search identifies a resource
|
||
that cannot be processed by the implementation, the program is ill-formed[.](#gen-6.sentence-1)
|
||
|
||
[*Note [1](#gen-note-1)*:
|
||
|
||
If the resource cannot be processed, the program is ill-formed
|
||
even when processing #embed with limit(0) ([[cpp.embed.param.limit]](#param.limit "15.4.2.1 limit parameter"))
|
||
or evaluating __has_embed[.](#gen-6.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[7](#gen-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L898)
|
||
|
||
*Recommended practice*: A mechanism similar to, but distinct from, theimplementation-defined
|
||
search paths used for #include ([[cpp.include]](cpp.include "15.3 Source file inclusion"))
|
||
is encouraged[.](#gen-7.sentence-1)
|
||
|
||
[8](#gen-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L904)
|
||
|
||
Either form of the #embed directive processes the[*pp-tokens*](cpp.pre#nt:pp-tokens "15.1 Preamble [cpp.pre]"), if present, just as in normal text[.](#gen-8.sentence-1)
|
||
|
||
The [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1 Preamble [cpp.pre]") shall then have the form[*embed-parameter-seq*](cpp.pre#nt:embed-parameter-seq "15.1 Preamble [cpp.pre]")[.](#gen-8.sentence-2)
|
||
|
||
[9](#gen-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L910)
|
||
|
||
A resource is a source of data accessible from the translation environment[.](#gen-9.sentence-1)
|
||
|
||
A resource has an [*implementation-resource-width*](#def:implementation-resource-width "15.4.1 General [cpp.embed.gen]"), which is theimplementation-defined
|
||
size in bits of the resource[.](#gen-9.sentence-2)
|
||
|
||
If the implementation-resource-width is not an integral multiple ofCHAR_BIT, the program is ill-formed[.](#gen-9.sentence-3)
|
||
|
||
Let [*implementation-resource-count*](#def:implementation-resource-count "15.4.1 General [cpp.embed.gen]") be
|
||
implementation-resource-width divided by CHAR_BIT[.](#gen-9.sentence-4)
|
||
|
||
Every resource also has a [*resource-count*](#def:resource-count "15.4.1 General [cpp.embed.gen]"), which is
|
||
|
||
- [(9.1)](#gen-9.1)
|
||
|
||
the value as computed from the optionally-provided limit[*embed-parameter*](cpp.pre#nt:embed-parameter "15.1 Preamble [cpp.pre]") ([[cpp.embed.param.limit]](#param.limit "15.4.2.1 limit parameter")), if present;
|
||
|
||
- [(9.2)](#gen-9.2)
|
||
|
||
otherwise, the implementation-resource-count.
|
||
|
||
A resource is empty if the resource-count is zero[.](#gen-9.sentence-6)
|
||
|
||
[10](#gen-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L931)
|
||
|
||
[*Example [1](#gen-example-1)*: // ill-formed if the implementation-resource-width is 6 bits#embed "6_bits.bin" â *end example*]
|
||
|
||
[11](#gen-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L939)
|
||
|
||
The #embed directive is replaced by a comma-separated list of integer
|
||
literals of type int, unless otherwise modified by embed
|
||
parameters ([[cpp.embed.param]](#param "15.4.2 Embed parameters"))[.](#gen-11.sentence-1)
|
||
|
||
[12](#gen-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L944)
|
||
|
||
The integer literals in the comma-separated list correspond to
|
||
resource-count consecutive calls to std::fgetc ([[cstdio.syn]](cstdio.syn "31.13.1 Header <cstdio> synopsis"))
|
||
from the resource, as a binary file[.](#gen-12.sentence-1)
|
||
|
||
If any call to std::fgetc returns EOF, the program is
|
||
ill-formed[.](#gen-12.sentence-2)
|
||
|
||
[13](#gen-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L951)
|
||
|
||
*Recommended practice*: The value of each integer literal should closely represent
|
||
the bit stream of the resource unmodified[.](#gen-13.sentence-1)
|
||
|
||
This can require an implementation to consider potential differences between
|
||
translation and execution environments, as well as any other applicable
|
||
sources of mismatch[.](#gen-13.sentence-2)
|
||
|
||
[*Example [2](#gen-example-2)*: #include <cstring>#include <cstddef>#include <fstream>#include <vector>#include <cassert>int main() {// If the file is the same as the resource in the translation environment, no assert in this program should fail.constexpr unsigned char d[] = {#embed <data.dat>}; const std::vector<unsigned char> vec_d = {#embed <data.dat>}; constexpr std::size_t expected_size = sizeof(d); // same file in execution environment as was embedded std::ifstream f_source("data.dat", std::ios::binary | std::ios::in); unsigned char runtime_d[expected_size]; char* ifstream_ptr = reinterpret_cast<char*>(runtime_d);
|
||
assert(!f_source.read(ifstream_ptr, expected_size));
|
||
std::size_t ifstream_size = f_source.gcount();
|
||
assert (ifstream_size == expected_size); int is_same = std::memcmp(&d[0], ifstream_ptr, ifstream_size);
|
||
assert(is_same == 0); int is_same_vec = std::memcmp(vec_d.data(), ifstream_ptr, ifstream_size);
|
||
assert(is_same_vec == 0);} â *end example*]
|
||
|
||
[*Example [3](#gen-example-3)*: int i = {#embed "i.dat"}; // well-formed if i.dat produces a single valueint i2 =#embed "i.dat" ; // also well-formed if i.dat produces a single valuestruct s {double a, b, c; struct { double e, f, g; } x; double h, i, j;};
|
||
s x = {// well-formed if the directive produces nine or fewer values#embed "s.dat"}; â *end example*]
|
||
|
||
[14](#gen-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L1012)
|
||
|
||
A preprocessing directive of the form
|
||
|
||
# embed [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1 Preamble [cpp.pre]") [*new-line*](cpp.pre#nt:new-line "15.1 Preamble [cpp.pre]")
|
||
|
||
(that does not match the previous form) is permitted[.](#gen-14.sentence-1)
|
||
|
||
The preprocessing tokens after embed in the directive are processed
|
||
just as in normal text (i.e., each identifier currently defined as a macro
|
||
name is replaced by its replacement list of preprocessing tokens)[.](#gen-14.sentence-2)
|
||
|
||
Then, an attempt is made to form a [*header-name*](lex.header#nt:header-name "5.6 Header names [lex.header]") preprocessing token ([[lex.header]](lex.header "5.6 Header names")) from the whitespace and the characters
|
||
of the spellings of the resulting sequence of preprocessing tokens immediately after embed;
|
||
the treatment of whitespace
|
||
is implementation-defined[.](#gen-14.sentence-3)
|
||
|
||
If the attempt succeeds, the directive with the so-formed [*header-name*](lex.header#nt:header-name "5.6 Header names [lex.header]") is processed as specified for the previous form[.](#gen-14.sentence-4)
|
||
|
||
Otherwise, the program is ill-formed[.](#gen-14.sentence-5)
|
||
|
||
[*Note [2](#gen-note-2)*:
|
||
|
||
Adjacent [*string-literal*](lex.string#nt:string-literal "5.13.5 String literals [lex.string]")*s* are not concatenated into a single[*string-literal*](lex.string#nt:string-literal "5.13.5 String literals [lex.string]") (see the translation phases in [[lex.phases]](lex.phases "5.2 Phases of translation"));
|
||
thus, an expansion that results in two [*string-literal*](lex.string#nt:string-literal "5.13.5 String literals [lex.string]")*s* is an
|
||
invalid directive[.](#gen-14.sentence-6)
|
||
|
||
â *end note*]
|
||
|
||
Any further processing as in normal text described for the previous
|
||
form is not performed[.](#gen-14.sentence-7)
|
||
|
||
[*Note [3](#gen-note-3)*:
|
||
|
||
That is, processing as in normal text happens once and only once for the entire
|
||
directive[.](#gen-14.sentence-8)
|
||
|
||
â *end note*]
|
||
|
||
[*Example [4](#gen-example-4)*:
|
||
|
||
If the directive matches the second form, the whole directive is replaced[.](#gen-14.sentence-9)
|
||
|
||
If the directive matches the first form, everything after the name is replaced[.](#gen-14.sentence-10)
|
||
|
||
#define EMPTY#define X myfile#define Y rsc#define Z 42#embed <myfile.rsc> prefix(Z)#embed EMPTY <X.Y> prefix(Z) is equivalent to:#embed <myfile.rsc> prefix(42)#embed <myfile.rsc> prefix(42)
|
||
|
||
â *end example*]
|
||
|
||
### [15.4.2](#param) Embed parameters [[cpp.embed.param]](cpp.embed.param)
|
||
|
||
#### [15.4.2.1](#param.limit) limit parameter [[cpp.embed.param.limit]](cpp.embed.param.limit)
|
||
|
||
[1](#param.limit-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L1063)
|
||
|
||
An [*embed-parameter*](cpp.pre#nt:embed-parameter "15.1 Preamble [cpp.pre]") of the formlimit ( [*pp-balanced-token-seq*](cpp.pre#nt:pp-balanced-token-seq "15.1 Preamble [cpp.pre]") ) specifies the
|
||
maximum possible number of elements in the comma-delimited list[.](#param.limit-1.sentence-1)
|
||
|
||
It shall appear at most once in the [*embed-parameter-seq*](cpp.pre#nt:embed-parameter-seq "15.1 Preamble [cpp.pre]")[.](#param.limit-1.sentence-2)
|
||
|
||
The preprocessing token defined shall not appear in the[*pp-balanced-token-seq*](cpp.pre#nt:pp-balanced-token-seq "15.1 Preamble [cpp.pre]")[.](#param.limit-1.sentence-3)
|
||
|
||
[2](#param.limit-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L1072)
|
||
|
||
The [*pp-balanced-token-seq*](cpp.pre#nt:pp-balanced-token-seq "15.1 Preamble [cpp.pre]") is evaluated as a[*constant-expression*](expr.const#nt:constant-expression "7.7 Constant expressions [expr.const]") using the rules as described in conditional
|
||
inclusion ([[cpp.cond]](cpp.cond "15.2 Conditional inclusion")), but without being processed as in normal text an
|
||
additional time[.](#param.limit-2.sentence-1)
|
||
|
||
[*Example [1](#param.limit-example-1)*: #undef DATA_LIMIT#if __has_embed(<data.dat> limit(DATA_LIMIT))#endif
|
||
|
||
is equivalent to:
|
||
|
||
#if __has_embed(<data.dat> limit(0))#endif â *end example*]
|
||
|
||
[*Example [2](#param.limit-example-2)*: #embed <data.dat> limit(__has_include("a.h"))#if __has_embed(<data.dat> limit(__has_include("a.h")))// ill-formed: __has_include ([[cpp.cond]](cpp.cond "15.2 Conditional inclusion")) cannot appear here#endif â *end example*]
|
||
|
||
[3](#param.limit-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L1103)
|
||
|
||
The [*constant-expression*](expr.const#nt:constant-expression "7.7 Constant expressions [expr.const]") shall be an integral constant expression
|
||
whose value is greater than or equal to zero[.](#param.limit-3.sentence-1)
|
||
|
||
The resource-count ([[cpp.embed.gen]](#gen "15.4.1 General")) becomes
|
||
implementation-resource-count, if the value of the[*constant-expression*](expr.const#nt:constant-expression "7.7 Constant expressions [expr.const]") is greater than
|
||
implementation-resource-count; otherwise, the value of the[*constant-expression*](expr.const#nt:constant-expression "7.7 Constant expressions [expr.const]")[.](#param.limit-3.sentence-2)
|
||
|
||
[*Example [3](#param.limit-example-3)*: constexpr unsigned char sound_signature[] = {// a hypothetical resource capable of expanding to four or more elements#embed <sdk/jump.wav> limit(2+2)};
|
||
|
||
static_assert(sizeof(sound_signature) == 4); // OK â *end example*]
|
||
|
||
#### [15.4.2.2](#param.prefix) prefix parameter [[cpp.embed.param.prefix]](cpp.embed.param.prefix)
|
||
|
||
[1](#param.prefix-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L1123)
|
||
|
||
An [*embed-parameter*](cpp.pre#nt:embed-parameter "15.1 Preamble [cpp.pre]") of the form
|
||
|
||
prefix ( [*pp-balanced-token-seq*](cpp.pre#nt:pp-balanced-token-seq "15.1 Preamble [cpp.pre]")opt )
|
||
|
||
shall appear at most once in the [*embed-parameter-seq*](cpp.pre#nt:embed-parameter-seq "15.1 Preamble [cpp.pre]")[.](#param.prefix-1.sentence-1)
|
||
|
||
[2](#param.prefix-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L1130)
|
||
|
||
If the resource is empty, this [*embed-parameter*](cpp.pre#nt:embed-parameter "15.1 Preamble [cpp.pre]") is ignored[.](#param.prefix-2.sentence-1)
|
||
|
||
Otherwise, the [*pp-balanced-token-seq*](cpp.pre#nt:pp-balanced-token-seq "15.1 Preamble [cpp.pre]") is placed immediately
|
||
before the comma-delimited list of integral literals[.](#param.prefix-2.sentence-2)
|
||
|
||
#### [15.4.2.3](#param.suffix) suffix parameter [[cpp.embed.param.suffix]](cpp.embed.param.suffix)
|
||
|
||
[1](#param.suffix-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L1136)
|
||
|
||
An [*embed-parameter*](cpp.pre#nt:embed-parameter "15.1 Preamble [cpp.pre]") of the form
|
||
|
||
suffix ( [*pp-balanced-token-seq*](cpp.pre#nt:pp-balanced-token-seq "15.1 Preamble [cpp.pre]")opt )
|
||
|
||
shall appear at most once in the [*embed-parameter-seq*](cpp.pre#nt:embed-parameter-seq "15.1 Preamble [cpp.pre]")[.](#param.suffix-1.sentence-1)
|
||
|
||
[2](#param.suffix-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L1143)
|
||
|
||
If the resource is empty, this [*embed-parameter*](cpp.pre#nt:embed-parameter "15.1 Preamble [cpp.pre]") is ignored[.](#param.suffix-2.sentence-1)
|
||
|
||
Otherwise, the [*pp-balanced-token-seq*](cpp.pre#nt:pp-balanced-token-seq "15.1 Preamble [cpp.pre]") is placed immediately after
|
||
the comma-delimited list of the integral constant expressions[.](#param.suffix-2.sentence-2)
|
||
|
||
[*Example [1](#param.suffix-example-1)*: constexpr unsigned char whl[] = {#embed "ches.glsl" \
|
||
prefix(0xEF, 0xBB, 0xBF, ) /* a sequence of bytes */ \
|
||
suffix(,)0};// always null-terminated, contains the sequence if not emptyconstexpr bool is_empty = sizeof(whl) == 1 && whl[0] == '\0';constexpr bool is_not_empty = sizeof(whl) >= 4&& whl[sizeof(whl) - 1] == '\0'&& whl[0] == '\xEF' && whl[1] == '\xBB' && whl[2] == '\xBF';static_assert(is_empty || is_not_empty); â *end example*]
|
||
|
||
#### [15.4.2.4](#param.if.empty) if_empty parameter [[cpp.embed.param.if.empty]](cpp.embed.param.if.empty)
|
||
|
||
[1](#param.if.empty-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L1166)
|
||
|
||
An embed-parameter of the form
|
||
|
||
if_empty ( [*pp-balanced-token-seq*](cpp.pre#nt:pp-balanced-token-seq "15.1 Preamble [cpp.pre]")opt )
|
||
|
||
shall appear at most once in the [*embed-parameter-seq*](cpp.pre#nt:embed-parameter-seq "15.1 Preamble [cpp.pre]")[.](#param.if.empty-1.sentence-1)
|
||
|
||
[2](#param.if.empty-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L1173)
|
||
|
||
If the resource is not empty, this [*embed-parameter*](cpp.pre#nt:embed-parameter "15.1 Preamble [cpp.pre]") is ignored[.](#param.if.empty-2.sentence-1)
|
||
|
||
Otherwise, the #embed directive is replaced by the[*pp-balanced-token-seq*](cpp.pre#nt:pp-balanced-token-seq "15.1 Preamble [cpp.pre]")[.](#param.if.empty-2.sentence-2)
|
||
|
||
[*Example [1](#param.if.empty-example-1)*:
|
||
|
||
limit(0) affects when a resource is considered empty[.](#param.if.empty-2.sentence-3)
|
||
|
||
Therefore, the following program:
|
||
|
||
#embed </owo/uwurandom> \
|
||
if_empty(42203) limit(0) expands to42203
|
||
|
||
â *end example*]
|
||
|
||
[*Example [2](#param.if.empty-example-2)*:
|
||
|
||
This resource is considered empty due to the limit(0) [*embed-parameter*](cpp.pre#nt:embed-parameter "15.1 Preamble [cpp.pre]"),
|
||
always, including in __has_embed clauses[.](#param.if.empty-2.sentence-6)
|
||
|
||
int infinity_zero () {#if __has_embed(</owo/uwurandom> limit(0) prefix(some tokens)) == __STDC_EMBED_EMPTY__ // if </owo/uwurandom> exists, this conditional inclusion branch is taken and the function returns 0.return 0;#else// otherwise, the resource does not exist#error "The resource does not exist"#endif} â *end example*]
|