Resource inclusion (since C++26)
#embed 是一个用于包含 资源 的预处理器指令。
目录 |
语法
#embed <
h-字符序列
>
预处理记号
换行
|
(1) | ||||||||
#embed "
q-字符序列
"
预处理记号
换行
|
(2) | ||||||||
#embed
预处理记号
换行
|
(3) | ||||||||
__has_embed
(
平衡预处理记号
)
|
(4) | ||||||||
| new-line | - | 换行符 |
| h-char-sequence | - |
一个或多个
h-char
组成的序列(参见
#include
)
|
| q-char-sequence | - |
一个或多个
q-char
组成的序列(参见
#include
)
|
| pp-tokens | - | 一个或多个 预处理记号 组成的序列 |
| balanced-pp-tokens | - | 一个或多个预处理记号组成的序列,其中所有 ( 、 [ 和 { 都正确闭合 |
说明
embed
之后的预处理令牌会像普通文本一样被处理(即每个当前被定义为宏名称的标识符会被其预处理令牌的替换列表所替代)。
- 若该指令不满足 #embed 指令的语法要求,则程序非良构。
-
若资源搜索成功且构造指令中的所有给定
embed参数
均受支持,则当资源非空时
__has_embed表达式求值为 __STDC_EMBED_FOUND__ ,资源为空时求值为 __STDC_EMBED_EMPTY__ 。 -
否则,
__has_embed表达式求值为 __STDC_EMBED_NOT_FOUND__ 。
资源
一个 资源 是指从翻译环境中可访问的数据源。资源具有 实现定义资源宽度 ,这是实现定义的资源位宽。若实现定义资源宽度不是 CHAR_BIT 的整数倍,则程序非良构。
令
implementation-resource-count
为 implementation-resource-width 除以
CHAR_BIT
。每个资源还具有一个
resource-count
,该值默认为 implementation-resource-count,除非提供了
limit
嵌入参数。
当资源计数为零时,该资源即为 空 。
// 如果实现资源宽度为6位则格式错误 #embed "6_bits.bin"
嵌入资源
除非另有修改, #embed 指令会被替换为以逗号分隔的 整数字面量 列表,其类型为 int 。
逗号分隔列表中的整数字面量对应于从资源中连续调用 std::fgetc 的次数(作为二进制文件处理)。如果任何一次对 std::fgetc 的调用返回 EOF ,则程序格式错误。
int i = { #embed "i.dat" }; // 当 i.dat 生成单个值时符合语法规范 int i2 = #embed "i.dat" ; // 当 i.dat 生成单个值时同样符合语法规范 struct T { double a, b, c; struct { double e, f, g; } x; double h, i, j; }; T x = { // 当指令生成九个或更少数值时符合语法规范 #embed "s.dat" };
嵌入参数
如果语法 (1) 或语法 (2) 中存在 pp-tokens ,其处理方式与普通文本相同。处理后的 pp-tokens 应构成一个 嵌入参数 序列,否则程序格式错误。嵌入参数具有以下语法:
limit
(
balanced-pp-tokens
)
|
(1) | ||||||||
prefix
(
balanced-pp-tokens
(可选)
)
|
(2) | ||||||||
suffix
(
balanced-pp-tokens
(可选)
)
|
(3) | ||||||||
if_empty
(
balanced-pp-tokens
(可选)
)
|
(4) | ||||||||
identifier
::
identifier
|
(5) | ||||||||
identifier
::
identifier
(
balanced-pp-tokens
(可选)
)
|
(6) | ||||||||
limit
参数
形式为
limit
(
balanced-pp-tokens
)
的嵌入参数在每个
#embed
指令中最多只能出现一次。
balanced-pp-tokens
会像普通文本一样被处理以形成
常量表达式
,但
defined
、
__has_include
、
__has_cpp_attribute
和
__has_embed
表达式不会被求值。
常量表达式必须是一个 整型常量表达式 ,其值必须大于等于零:
- 若常量表达式的值大于实现资源计数,则资源计数仍为实现资源计数。
- 否则,资源计数将变为常量表达式的值。
constexpr unsigned char sound_signature[] = { // 一个能够扩展至四个或更多元素的假设资源 #embed <sdk/jump.wav> limit(2 + 2) }; static_assert(sizeof(sound_signature) == 4); // 等价于 #embed <data.dat> limit(10) #define DATA_LIMIT 10 #embed <data.dat> limit(DATA_LIMIT) // 非良构 #embed <data.dat> limit(__has_include("a.h"))
prefix
参数
形式为
prefix
(
balanced-pp-tokens
(可选)
)
的嵌入参数在每个
#embed
指令中最多只能出现一次。
如果资源为空,则忽略此嵌入参数。否则, balanced-pp-tokens 将紧置于逗号分隔的整数字面值列表之前。
suffix
参数
后缀形式的嵌入参数
suffix
(
balanced-pp-tokens
(可选)
)
在每个
#embed
指令中最多只能出现一次。
如果资源为空,则忽略此嵌入参数。否则, balanced-pp-tokens 将紧跟在逗号分隔的整数字面值列表之后。
constexpr unsigned char whl[] = { #embed "chess.glsl" \ prefix(0xEF, 0xBB, 0xBF, ) /∗ 字节序列 ∗/ \ suffix(,) 0 }; // 始终以空字符结尾,非空时包含序列 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
参数
形式为
if_empty
(
balanced-pp-tokens
(optional)
)
的嵌入参数在每个
#embed
指令中最多只能出现一次。
若资源 非 空,则忽略此嵌入参数。否则, #embed 指令将被 balanced-pp-tokens 替换。
// 无论 /owo/uwurandom 的内容如何,始终展开为 42203 #embed </owo/uwurandom> if_empty(42203) limit(0)
注释
| 功能测试宏 | 值 | 标准 | 功能 |
|---|---|---|---|
__cpp_pp_embed
|
202502L
|
(C++26) | #embed 指令 |
示例
演示
#embed
的效果。若
data.dat
能在翻译环境中作为资源嵌入,本程序中的所有断言均不应触发失败。
#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); // 执行环境中与嵌入内容相同的文件 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); }
参考文献
- C++26 标准 (ISO/IEC 14882:2026):
-
- 15.4 资源嵌入 [cpp.embed]
参见
|
C 文档
关于
二进制资源包含
(自 C23 起)
|