资源包含 (C++26 起)
#embed 是用於包含資源的預處理器指令。
語法
#embed < h字符序列 > 記號序列 換行
|
(1) | ||||||||
#embed " q字符序列 " 記號序列 換行
|
(2) | ||||||||
#embed 記號序列 換行
|
(3) | ||||||||
__has_embed ( 平衡記號序列 )
|
(4) | ||||||||
| 換行 | - | 換行字符 |
| h字符序列 | - | 一個或多個h字符 的序列(見 #include)
|
| q字符序列 | - | 一個或多個q字符 的序列(見 #include)
|
| 記號序列 | - | 一個或多個預處理記號的序列 |
| 平衡記號序列 | - | 一個或多個預處理記號的序列,其中每個 (、[ 和 { 都有正確關閉
|
解釋
> 字符,如果存在)作為語法 (1) 中所需的序列。embed 後面的預處理記號會按在正常文本中進行處理(即每個目前定義為宏名的標識符都會被替換為它的預處理記號替換列表)。< 和 > 之間或一對 " 字符之前的預處理記號序列合併為單個資源預處理記號的方法由實現定義。#embed 指令的記號序列 並搜索資源。
- 如果剛才的語法 (3) 指令不滿足
#embed指令的語法要求,那麼程序非良構。 - 否則,如果資源搜索成功且所有給定的嵌入參數均受支持,那麼
__has_embed表達式在資源非空時求值為__STDC_EMBED_FOUND__,在資源為空時求值為__STDC_EMBED_EMPTY__。 - 否則
__has_embed表達式求值為__STDC_EMBED_NOT_FOUND__。
資源
資源 是可以從翻譯環境訪問的數據源。資源具有實現資源寬度,它是由實現定義的以位表示的資源大小。如果實現資源寬度不是 CHAR_BIT 的整數倍數,那麼程序非良構。
設實現資源計數 為實現資源寬度除以 CHAR_BIT 的結果。每個資源也具有資源計數,它是實現資源計數本身,除非提供了 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) 中有出現記號序列,那麼它會按在正常文本中進行處理。處理後的記號序列 應組成一個嵌入參數 序列,否則程序非良構。嵌入參數具有以下語法:
limit ( 平衡記號序列 )
|
(1) | ||||||||
prefix ( 平衡記號序列 (可選) )
|
(2) | ||||||||
suffix ( 平衡記號序列 (可選) )
|
(3) | ||||||||
if_empty ( 平衡記號序列 (可選) )
|
(4) | ||||||||
標識符 :: 標識符
|
(5) | ||||||||
標識符 :: 標識符 ( 平衡記號序列 (可選) )
|
(6) | ||||||||
limit 參數
形式為 limit ( 平衡記號序列 ) 的嵌入參數在每個 #embed 指令中最多只能出現一次。
平衡記號序列 會按在正常文本中進行處理以組成常量表達式,但不會對 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);
// 等价于 to #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 ( 平衡記號序列 (可選) ) 的嵌入參數在每個 #embed 指令中最多只能出現一次。
如果資源為空,那麼忽略此嵌入參數。否則將平衡記號序列 放在緊接在逗號分隔的整數字面量列表之前的位置。
suffix 參數
形式為 suffix ( 平衡記號序列 (可選) ) 的嵌入參數在每個 #embed 指令中最多只能出現一次。
如果資源為空,那麼忽略此嵌入參數。否則將平衡記號序列 放在緊接在逗號分隔的整數字面量列表之後的位置。
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 ( 平衡記號序列 (可選) ) 的嵌入參數在每個 #embed 指令中最多只能出現一次。
如果資源不為空,那麼忽略此嵌入參數。否則以平衡記號序列 替換該 #embed 指令。
// 无论 /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 Resource inclusion [cpp.embed]
參閱
二進制資源包含 (C23 起)的 C 文檔
|