Включение ресурсов (начиная с C++26)
#embed — директива препроцессора для включения ресурсов.
Синтаксис
#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 | - | Символ новой строки |
| h-char-sequence | - | Последовательность из одного или нескольких символов h-char (см. #include) |
| q-char-sequence | - | Последовательность из одного или нескольких символов q-char (см. #include) |
| pp-tokens | - | Последовательность из одного или нескольких токенов препроцессора |
| balanced-pp-tokens | - | Последовательность из одного или нескольких токенов препроцессора, в которой все (, [ и { корректно закрыты |
Пояснение
>, если они есть) исходной директивы.embed в директиве обрабатываются так же, как в обычном тексте (то есть каждый идентификатор, в данный момент определённый как имя макроса, заменяется списком токенов препроцессора из его подстановки).< и > или парой символов " в один токен препроцессора с именем ресурса определяется реализацией.- Если такая директива не удовлетворяет синтаксическим требованиям директивы #embed, программа некорректна.
- В противном случае, если поиск ресурса завершается успешно и поддерживаются все заданные параметры встраивания вымышленной директивы, выражение
__has_embedвычисляется в__STDC_EMBED_FOUND__, если ресурс не пуст, и в__STDC_EMBED_EMPTY__, если ресурс пуст. - В противном случае выражение
__has_embedвычисляется в__STDC_EMBED_NOT_FOUND__.
Ресурсы
Ресурс — это источник данных, доступный из среды трансляции. Ресурс имеет ширину ресурса реализации — определяемый реализацией размер ресурса в битах. Если ширина ресурса реализации не кратна CHAR_BIT, программа некорректна.
Пусть количество ресурсов реализации равно ширине ресурса реализации, делённой на CHAR_BIT. Каждый ресурс также имеет количество элементов ресурса , равное количеству ресурсов реализации, если только не задан параметр встраивания limit.
Ресурс является пустым, если количество его элементов равно нулю.
// ill-formed if the implementation-resource-width is 6 bits #embed "6_bits.bin"
Встраивание ресурсов
Если не изменено иным образом, директива #embed заменяется списком целочисленных литералов типа int, разделённых запятыми.
Целочисленные литералы в списке, разделённом запятыми, соответствуют последовательным вызовам std::fgetc к ресурсу как к двоичному файлу в количестве, равном количеству элементов ресурса. Если какой-либо вызов std::fgetc возвращает EOF, программа некорректна.
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"
};
Параметры встраивания
Если в синтаксисе (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[] =
{
// 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"))
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, ) /∗ a sequence of bytes ∗/ \
suffix(,)
0
};
// always null-terminated, contains the sequence if not empty
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 (необязательно) ) может встречаться не более одного раза в каждой директиве #embed.
Если ресурс не пуст, этот параметр встраивания игнорируется. В противном случае директива #embed заменяется на balanced-pp-tokens.
// always expands to 42203 regardless of the content of /owo/uwurandom #embed </owo/uwurandom> if_empty(42203) limit(0)
Примечания
| Макрос проверки поддержки функции | Значение | Стандарт | Функция |
|---|---|---|---|
__cpp_pp_embed | 202502L | (C++26) | Директива #embed |
Пример
Демонстрация эффекта директивы #embed. Если data.dat можно встроить как ресурс в среде трансляции, ни одна проверка assert в этой программе не должна завершиться неудачей.
#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);
}
Ссылки
- Стандарт C++26 (ISO/IEC 14882:2026):
- 15.4 Включение ресурсов [cpp.embed]
См. также
| Документация по C для Включение двоичных ресурсов (начиная с C23) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/preprocessor/embed