LANGUAGES Signal 410
C++26: #embed
Illustration only Photo by Bruno Martins on Unsplash
C++26 introduces #embed, a preprocessor directive that includes binary files as byte arrays at compile time, eliminating the need for external tools or build-system hacks.
Engineers can now embed binary resources like certificates or images directly in source code without fragile external scripts or generated files. This reduces build complexity and the risk of stale data, but requires the resource file to be present at compile time and adds a new preprocessor dependency.
Written by elseif from the cluster below · every claim links back to a sourceThe three things worth knowing
#embed expands to a comma-separated list of integer constant expressions, one per byte of the resource file, usable in array initializers.
Parameters limit, prefix, suffix, and if_empty control embedding behavior, with careful comma syntax to avoid token concatenation errors.
__has_embed provides compile-time detection of resource existence, returning __STDC_EMBED_FOUND__ or __STDC_EMBED_NOT_FOUND__.
THE READ
What elseif makes of it.
The #embed directive replaces the common practice of using tools like xxd -i, objcopy, or custom Python scripts to convert binary files into C arrays. It is a preprocessor directive, not a constexpr function, meaning it operates before compilation proper. The syntax mirrors #include: double quotes for local paths, angle brackets for system resource paths. Four optional parameters, limit, prefix, suffix, and if_empty, give fine-grained control over the embedded data.
Adopting #embed requires updating build systems to ensure resource files are available at the preprocessor stage, which may not be trivial for projects that generate resources during the build. The limit parameter can reduce binary size by embedding only a header or prefix, but it demands knowledge of the file's structure. The prefix and suffix parameters have a non-obvious comma syntax: a trailing comma in prefix and a leading comma in suffix are necessary to separate tokens correctly, which is a potential source of bugs.
The directive stops working when the resource file is not present at compile time; __has_embed can guard against this, but it adds conditional compilation branches. The if_empty parameter only applies when the file exists but is zero bytes, it does not handle missing files. For dynamic resources that change at runtime, #embed is not suitable; it is purely a compile-time mechanism. The preprocessor-based design means the resource must be a file, not a generated constant or a runtime value.
The standardization process took five years and fourteen revisions, with an earlier proposal (P1040) advocating a constexpr function approach that failed to gain consensus. The final design is a preprocessor directive, which was seen as simpler and more predictable. This history highlights the difficulty of adding language features that touch both the preprocessor and the type system, and the trade-offs between compile-time flexibility and implementation complexity.
For working engineers, #embed simplifies a common task but introduces a new compile-time dependency. Projects that currently use external tools will need to migrate their build scripts to ensure resource files are in the include path. The feature is part of C++26, so compiler support will be required; until then, existing workarounds remain necessary. The directive's parameters offer enough flexibility to handle most embedding scenarios, but the comma syntax and if_empty behavior require careful reading of the specification.
Written by elseif from the cluster below · checked for specifics the sources never containedTHE CLUSTER