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

354 lines
18 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.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.1General[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.1General[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.6Header names[lex.header]") [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1Preamble[cpp.pre]")opt [*new-line*](cpp.pre#nt:new-line "15.1Preamble[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.6Header 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.6Header names[lex.header]") is of the form
< [*h-char-sequence*](lex.header#nt:h-char-sequence "5.6Header 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.6Header 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.6Header names[lex.header]") is of the form
" [*q-char-sequence*](lex.header#nt:q-char-sequence "5.6Header 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.6Header 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.1limit 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.3Source 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.1Preamble[cpp.pre]"), if present, just as in normal text[.](#gen-8.sentence-1)
The [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1Preamble[cpp.pre]") shall then have the form[*embed-parameter-seq*](cpp.pre#nt:embed-parameter-seq "15.1Preamble[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.1General[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.1General[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.1General[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.1Preamble[cpp.pre]") ([[cpp.embed.param.limit]](#param.limit "15.4.2.1limit 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.2Embed 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.1Header <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.1Preamble[cpp.pre]") [*new-line*](cpp.pre#nt:new-line "15.1Preamble[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.6Header names[lex.header]") preprocessing token ([[lex.header]](lex.header "5.6Header 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.6Header 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.5String literals[lex.string]")*s* are not concatenated into a single[*string-literal*](lex.string#nt:string-literal "5.13.5String literals[lex.string]") (see the translation phases in [[lex.phases]](lex.phases "5.2Phases of translation"));
thus, an expansion that results in two [*string-literal*](lex.string#nt:string-literal "5.13.5String 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.1Preamble[cpp.pre]") of the formlimit ( [*pp-balanced-token-seq*](cpp.pre#nt:pp-balanced-token-seq "15.1Preamble[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.1Preamble[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.1Preamble[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.1Preamble[cpp.pre]") is evaluated as a[*constant-expression*](expr.const#nt:constant-expression "7.7Constant expressions[expr.const]") using the rules as described in conditional
inclusion ([[cpp.cond]](cpp.cond "15.2Conditional 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.2Conditional 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.7Constant 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.1General")) becomes
implementation-resource-count, if the value of the[*constant-expression*](expr.const#nt:constant-expression "7.7Constant expressions[expr.const]") is greater than
implementation-resource-count; otherwise, the value of the[*constant-expression*](expr.const#nt:constant-expression "7.7Constant 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.1Preamble[cpp.pre]") of the form
prefix ( [*pp-balanced-token-seq*](cpp.pre#nt:pp-balanced-token-seq "15.1Preamble[cpp.pre]")opt )
shall appear at most once in the [*embed-parameter-seq*](cpp.pre#nt:embed-parameter-seq "15.1Preamble[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.1Preamble[cpp.pre]") is ignored[.](#param.prefix-2.sentence-1)
Otherwise, the [*pp-balanced-token-seq*](cpp.pre#nt:pp-balanced-token-seq "15.1Preamble[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.1Preamble[cpp.pre]") of the form
suffix ( [*pp-balanced-token-seq*](cpp.pre#nt:pp-balanced-token-seq "15.1Preamble[cpp.pre]")opt )
shall appear at most once in the [*embed-parameter-seq*](cpp.pre#nt:embed-parameter-seq "15.1Preamble[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.1Preamble[cpp.pre]") is ignored[.](#param.suffix-2.sentence-1)
Otherwise, the [*pp-balanced-token-seq*](cpp.pre#nt:pp-balanced-token-seq "15.1Preamble[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.1Preamble[cpp.pre]")opt )
shall appear at most once in the [*embed-parameter-seq*](cpp.pre#nt:embed-parameter-seq "15.1Preamble[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.1Preamble[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.1Preamble[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.1Preamble[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*]