1. Changelog
1.1. Revision 2 - June 5th, 2025
-
Design was expanded upon in Revision 1 and further explicated in this version to prevent people from being confused about what is being proposed here and what the specification was asking for. It was not recorded in the previous changelog: it is being recorded here.
-
Revision 2 does not add or change any of the wording in a way that matters; it just fixes clerical errors, typos, and aligns dates.
-
One such typo: fixes "It shall provide" to "It provides", as the "shall" is spurious in C++ wording since it does not provide anything.
-
§ 3 Design elaborates that this is meant to be that
applies beforeoffset
is applied, as what is implemented inlimit
andclang :: offset
today.gnu :: offset -
Some discussion during an SG22 meeting about restricting the order of embed parameters. This isn’t present in any implementation or in the C wording, and it’s an awful experience overall: rejected this design to proceed forward.
1.2. Revision 1 - February 14th, 2025
-
Minor typo and wording cleanup.
1.3. Revision 0 - December 13th, 2024
-
Initial release.
2. Introduction and Motivation
The goal is to add the extremely-popular and already-implemented
and
parameters as standard parameters. That is the only motivation of this proposal; to standardize existing practice.
Originally, users asked to add this parameter, but only after C23 standardized. Given the late stage that users have asked -- waiting until the very end -- it has to be added separately. This proposal aims to standardize what users have asked for, and what Clang and GCC have implemented.
3. Design
The design of
is straightforward:
-
discardsoffset
items, up to the full size of the resource;some - preprocessor - constant - value -
nothing happens if
evaluates tosome - preprocessor - constant - value
;0 -
if
is greater than or equal to the size of the resource, the resource is considered empty;offset -
does not shrink the file to a given size beforelimit
;offset
is applied to the original file size (called the "implementation-resource-count" in the wording).offset
These are the only tenets of the design, and match the practice for existing implementations
and
. It is also how the original author envisioned this when it was first PR’d to Clang, and the original tests (plus new ones) still pass in the LLVM/clang and gnu/gcc repositories.
There was some discussion during the June 4th, 2025 about the order of parameters. This turned into a significant enough change that it is a separate paper. No additional discussion or changes are proposed for this paper: it is exactly a standardization of existing practice and what was approved in Austria.
4. Wording
This wording is relative to C++'s latest working draft.
4.1. Intent
The intent of the wording is to provide a preprocessing directive that:
-
allows an
parameter skipping over a number of elements before beginning to write out elements to the comma-delimited list;offset -
and, applies to the actual size of the resource (and not to any applied
).limit
4.2. Proposed Language Wording
4.2.1. Add to the control-line production in §15.1 Preamble [cpp.pre] a new grammar production for offset
embed-standard-parameter:
limit ( pp-balanced-token-seq )
- offset ( pp-balanced-token-seq )
prefix ( pp-balanced-token-seqopt )
suffix ( pp-balanced-token-seqopt )
if_empty ( pp-balanced-token-seqopt )
4.2.2. Add a new sub-clause §15.4.2.✨ under Resource Inclusion for Embed parameters for the new offset
parameter [cpp.embed.param.offset]
15.4.2.✨parameter [cpp.embed.param.offset]
offset An embed-parameter of the form
denotes the number of elements to be skipped from the resource. It shall appear at most once in the embed-parameter-seq.
offset ( pp - balanced - token - seq ) The pp-balanced-token-seq is evaluated as a constant-expression using the rules as described in conditional inclusion ([cpp.cond]), but without being processed as in normal text an additional time.
The constant-expression shall be an integral constant expression whose value is greater than or equal to zero. It provides the value for resource-offset. The embed directive performs resource-offset consecutive calls to
([cstdio.syn]) from the resource, as a binary file. If a call to
std :: fgetc returns
std :: fgetc , the resouce is considered empty. Otherwise, the result of the call is discarded. The resource-count is changed to be
EOF
the value is computed using the
embed-parameter ([cpp.embed.param.limit]), if the
limit embed-parameter is present. Let the value computed by the
limit embed-parameter be limit-value. resource-count becomes $max(min(\text{limit-value}, \text{implementation-resource-count} - \text{resource-offset}), 0)$.
limit Otherwise, $max(\text{implementation-resource-count} - \text{resource-offset}, 0)$.
[Example:
constexpr const unsigned char sound_signature [] = { // a hypothetical resource capable of expanding to four or more elements #embed <sdk/jump.wav> limit(2+2) }; constexpr const unsigned char truncated_sound_signature [] = { // the same hypothetical resource capable of expanding to four or more elements #embed <sdk/jump.wav> offset(2) limit(2) }; static_assert ( sizeof ( sound_signature ) == 4 ); static_assert ( sizeof ( truncated_sound_signature ) == 2 ); static_assert ( sound_signature [ 2 ] == truncated_sound_signature [ 0 ]); static_assert ( sound_signature [ 3 ] == truncated_sound_signature [ 1 ]); – end example]
4.3. Add a new example to the if_empty
embed parameter [cpp.embed.if.empty] section
[Example: Given a resource
that has an implementation-resource-count of 1, the following directives:
< single_byte > #embed <single_byte> offset(1) if_empty(44203) #embed <single_byte> limit(0) offset(1) if_empty(44203) are replaced with:
42203 42203 – end example]
[Example: Given a resource
that has an implementation-resource-count of 1,
< single_byte > will be considered empty despite
__has_embed , as
limit ( 1 ) has exhausted the implementation-resource-count:
offset ( 1 ) int infinity_zero () { #if __has_embed(<single_byte> limit(1) offset(1) prefix(some tokens)) == __STDC_EMBED_EMPTY__ // if <single_byte> 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]