Spec-Zone.ru › C++

Включение ресурсов (начиная с 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)
1) Ищет ресурс, однозначно идентифицируемый с помощью h-char-sequence, и заменяет директиву всем содержимым ресурса.
2) Ищет ресурс, идентифицируемый с помощью q-char-sequence, и заменяет директиву всем содержимым исходного файла. В качестве запасного варианта может использоваться форма (1), а q-char-sequence может рассматриваться как идентификатор ресурса.
3) Если не подходит ни форма (1), ни форма (2), для pp-tokens выполняется макроподстановка. После подстановки директива снова проверяется на соответствие форме (1) или (2).
4) Проверяет, доступен ли ресурс для включения с заданными параметрами встраивания.
new-line - Символ новой строки
h-char-sequence - Последовательность из одного или нескольких символов h-char  (см. #include)
q-char-sequence - Последовательность из одного или нескольких символов q-char  (см. #include)
pp-tokens - Последовательность из одного или нескольких токенов препроцессора
balanced-pp-tokens - Последовательность из одного или нескольких токенов препроцессора, в которой все (, [ и { корректно закрыты

Пояснение

1) Ищет в последовательности мест ресурс, однозначно идентифицируемый с помощью h-char-sequence , и заменяет эту директиву всем содержимым заголовка. Способ задания мест поиска или идентификации заголовка определяется реализацией.
2) Заменяет эту директиву всем содержимым ресурса, идентифицируемого с помощью q-char-sequence . Поиск указанного ресурса выполняется способом, определяемым реализацией.
Если такой поиск не поддерживается или завершается неудачей, директива обрабатывается повторно так, как если бы она соответствовала синтаксису (1) с той же содержащейся в ней последовательностью (включая символы >, если они есть) исходной директивы.
3) Токены препроцессора после embed в директиве обрабатываются так же, как в обычном тексте (то есть каждый идентификатор, в данный момент определённый как имя макроса, заменяется списком токенов препроцессора из его подстановки).
Если директива, полученная после всех подстановок, не соответствует ни одной из двух предыдущих форм, поведение не определено.
Способ объединения последовательности токенов препроцессора между парой токенов препроцессора < и > или парой символов " в один токен препроцессора с именем ресурса определяется реализацией.
4) Ищет ресурс, идентифицируемый вымышленной директивой #embed с синтаксисом (3), используя balanced-pp-tokens в качестве pp-tokens.
  • Если такая директива не удовлетворяет синтаксическим требованиям директивы #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)
1-4) Стандартные параметры встраивания.
1) Ограничивает количество встраиваемых элементов ресурса.
2) Добавляет префикс перед встраиваемым непустым ресурсом.
3) Добавляет суффикс после встраиваемого непустого ресурса.
4) Заменяет встраиваемый ресурс, если он пуст.
5,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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API