Resource inclusion (since C++26)
#embed is a preprocessor directive to include resources .
Contents |
Syntax
#embed <
h-char-sequence
>
pp-tokens
new-line
|
(1) | ||||||||
#embed "
q-char-sequence
"
pp-tokens
new-line
|
(2) | ||||||||
#embed
pp-tokens
new-line
|
(3) | ||||||||
__has_embed
(
balanced-pp-tokens
)
|
(4) | ||||||||
| new-line | - | The new-line character |
| h-char-sequence | - |
A sequence of one or more
h-char
s (see
#include
)
|
| q-char-sequence | - |
A sequence of one or more
q-char
s (see
#include
)
|
| pp-tokens | - | A sequence of one or more preprocessing tokens |
| balanced-pp-tokens | - | A sequence of one or more preprocessing tokens, where all ( , [ and { are properly closed |
Explanation
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).
- If such a directive would not satisfy the syntactic requirements of an #embed directive, the program is ill-formed.
-
Otherwise, if the search for the resource succeeds and all the given
embed parameters
in the invented directive are supported, the
__has_embedexpression evaluates to __STDC_EMBED_FOUND__ if the resource is not empty, and to __STDC_EMBED_EMPTY__ if the resource is empty. -
Otherwise, the
__has_embedexpression evaluates to __STDC_EMBED_NOT_FOUND__ .
Resources
A resource is a source of data accessible from the translation environment. A resource has an implementation-resource-width , which is the implementation-defined size in bits of the resource. If the implementation-resource-width is not an integral multiple of CHAR_BIT , the program is ill-formed.
Let
implementation-resource-count
be implementation-resource-width divided by
CHAR_BIT
. Every resource also has a
resource-count
, which is the implementation-resource-count, unless the
limit
embed parameter is provided.
A resource is empty if the resource-count is zero.
// ill-formed if the implementation-resource-width is 6 bits #embed "6_bits.bin"
Embedding resources
Unless otherwise modified, the #embed directive is replaced by a comma-delimited list of integer literals of type int .
The integer literals in the comma-delimited list correspond to resource-count consecutive calls to std::fgetc from the resource, as a binary file. If any call to std::fgetc returns EOF , the program is ill-formed.
int i = { #embed "i.dat" }; // well-formed if i.dat produces a single value int i2 = #embed "i.dat" ; // also well-formed if i.dat produces a single value struct T { double a, b, c; struct { double e, f, g; } x; double h, i, j; }; T x = { // well-formed if the directive produces nine or fewer values #embed "s.dat" };
Embed parameters
If pp-tokens is present in syntax (1) or syntax (2) , it is processed just as in normal text. The processed pp-tokens should form a sequence of embed parameters , otherwise the program is ill-formed. Embed parameters have the following syntax:
limit
(
balanced-pp-tokens
)
|
(1) | ||||||||
prefix
(
balanced-pp-tokens
(optional)
)
|
(2) | ||||||||
suffix
(
balanced-pp-tokens
(optional)
)
|
(3) | ||||||||
if_empty
(
balanced-pp-tokens
(optional)
)
|
(4) | ||||||||
identifier
::
identifier
|
(5) | ||||||||
identifier
::
identifier
(
balanced-pp-tokens
(optional)
)
|
(6) | ||||||||
limit
parameter
An embed parameter of the form
limit
(
balanced-pp-tokens
)
can only appear at most once in each
#embed
directive.
balanced-pp-tokens
are processed just as in normal text to form a
constant expression
, but
defined
,
__has_include
,
__has_cpp_attribute
and
__has_embed
expressions are not evaluated.
The constant expression must be an integral constant expression whose value is greater than or equal to zero:
- If the value of the constant expression is greater than implementation-resource-count, the resource-count is still the implementation-resource-count.
- Otherwise, the resource-count becomes the value of the constant expression.
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); // equivalent to #embed <data.dat> limit(10) #define DATA_LIMIT 10 #embed <data.dat> limit(DATA_LIMIT) // ill-formed #embed <data.dat> limit(__has_include("a.h"))
prefix
parameter
An embed parameter of the form
prefix
(
balanced-pp-tokens
(optional)
)
can only appear at most once in each
#embed
directive.
If the resource is empty, this embed parameter is ignored. Otherwise, balanced-pp-tokens is placed immediately before the comma-delimited list of integral literals.
suffix
parameter
An embed parameter of the form
suffix
(
balanced-pp-tokens
(optional)
)
can only appear at most once in each
#embed
directive.
If the resource is empty, this embed parameter is ignored. Otherwise, balanced-pp-tokens is placed immediately after the comma-delimited list of integral literals.
constexpr unsigned char whl[] = { #embed "chess.glsl" \ prefix(0xEF, 0xBB, 0xBF, ) /∗ a sequence of bytes ∗/ \ suffix(,) 0 }; // always null-terminated, contains the sequence if not empty constexpr 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);
if_empty
parameter
An embed parameter of the form
if_empty
(
balanced-pp-tokens
(optional)
)
can only appear at most once in each
#embed
directive.
If the resource is not empty, this embed parameter is ignored. Otherwise, the #embed directive is replaced by balanced-pp-tokens .
// always expands to 42203 regardless of the content of /owo/uwurandom #embed </owo/uwurandom> if_empty(42203) limit(0)
Notes
| Feature-test macro | Value | Std | Feature |
|---|---|---|---|
__cpp_pp_embed
|
202502L
|
(C++26) | The #embed directive |
Example
Demonstrate the effect of
#embed
. If
data.dat
can be embedded as a resource in the translation environment, no assert in this program should fail.
#include <cassert> #include <cstddef> #include <cstring> #include <fstream> #include <vector> int main() { 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_base::binary | std::ios_base::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); }
References
- C++26 standard (ISO/IEC 14882:2026):
-
- 15.4 Resource inclusion [cpp.embed]
See also
|
C documentation
for
Binary resource inclusion
(since C23)
|