Resource inclusion (since C++26)
#embed is a preprocessor directive to include resources.
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
> characters, if any) from the original directive.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).< and a > preprocessing token pair or a pair of " characters is combined into a single resource name preprocessing token is implementation-defined.#embed directive of syntax (3), using balanced-pp-tokens as its pp-tokens.
- If such a directive would not satisfy the syntactic requirements of an
#embeddirective, 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 has a resource-offset , which is the value as computed from the optionally-provided offset embed-parameter, if present; otherwise, zero. |
(since C++29) |
|
Every resource also has a resource-count , which is the implementation-resource-count, unless the |
(since C++26) (until C++29) |
|
Every resource also has a resource-count , which is the value
|
(since C++29) |
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 modified by embed parameters, 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 |
(since C++26) (until C++29) |
|
First, resource-offset calls to std::fgetc from the resource as a binary file have their result discarded and ignored. Next, resource-count consecutive calls to std::fgetc produce the elements of the comma-separated list of integer literals, in order. If any of the resource-count calls to std::fgetc returns |
(since C++29) |
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) | ||||||||
offset ( balanced-pp-tokens )
|
(2) | (since C++29) | |||||||
prefix ( balanced-pp-tokens (optional) )
|
(3) | ||||||||
suffix ( balanced-pp-tokens (optional) )
|
(4) | ||||||||
if_empty ( balanced-pp-tokens (optional) )
|
(5) | ||||||||
identifier :: identifier
|
(6) | ||||||||
identifier :: identifier ( balanced-pp-tokens (optional) )
|
(7) | ||||||||
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.
|
(until C++29) |
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"))
offset parameter (since C++29)
An embed parameter of the form offset ( 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 (N) is greater than or equal to zero.
Informally:
offsetdiscards N items, up to the full size of the resource;- nothing happens if N evaluates to zero;
- if
offsetis greater than or equal to the size of the resource, the resource is considered empty; limitdoes not shrink the file to a given size beforeoffset;offsetis applied to the original file size.
// Assume resource <SDK/leap.ogg> below can expand to 4 or more bytes.
constexpr const unsigned char res[]
{
#embed <SDK/leap.ogg>
};
constexpr const unsigned char offset_res[]
{
#embed <SDK/leap.ogg> offset(2)
};
static_assert(res[2] == offset_res[0] and
res[3] == offset_res[1]);
constexpr const unsigned char offset_limit_res[]
{
#embed <SDK/leap.ogg> offset(1) limit(1)
};
static_assert(res[1] == offset_limit_res[0]);
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 and whl[0] == '\0';
constexpr bool is_not_empty = sizeof(whl) >= 4
and whl[sizeof(whl) - 1] == '\0'
and whl[0] == '\xEF'
and whl[1] == '\xBB'
and whl[2] == '\xBF';
static_assert(is_empty or 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)
// given a resource <single_byte> that has a size 1 byte, always
// expands to 42203 regardless of the content of <single_byte>
#embed <single_byte> offset(1) if_empty(42203)
Notes
| Feature-test macro | Value | Std | Feature |
|---|---|---|---|
__cpp_pp_embed |
202502L |
(C++26) | The #embed directive
|
202606L |
(C++29) | #embed offset parameter
|
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)
|