Namespaces
Variants

Binary resource inclusion (since C23)

From cppreference.net

#embed — это директива препроцессора для включения (бинарных) ресурсов в сборку, где ресурс определяется как источник данных, доступный из среды трансляции.

Содержание

Синтаксис

#embed < h-char-sequence > embed-parameter-sequence  (необязательно) new-line (1)
#embed " q-char-sequence " embed-parameter-sequence  (необязательно) new-line (2)
#embed pp-tokens new-line (3)
__has_embed ( " q-char-sequence " embed-parameter-sequence  (необязательно) )
__has_embed ( < h-char-sequence > embed-parameter-sequence  (необязательно) )
(4)
__has_embed ( string-literal pp-balanced-token-sequence  (необязательно) )
__has_embed ( < h-pp-tokens > pp-balanced-token-sequence  (необязательно) )
(5)
1) Выполняет поиск ресурса, однозначно идентифицируемого с помощью h-char-sequence и заменяет директиву разделённым запятыми списком целых чисел, соответствующих данным ресурса.
2) Выполняет поиск ресурса, идентифицированного q-char-sequence и заменяет директиву списком целых чисел, соответствующих данным ресурса. Может переходить к (1) .
3) Если ни (1) ни (2) не совпадают, pp-tokens подвергнутся макроподстановке. Директива после подстановки будет снова проверяться на соответствие с (1) или (2) .
4) Проверяет, доступен ли ресурс для встраивания, является ли он пустым или нет, и поддерживаются ли переданные параметры реализацией.
5) Если (4) не совпадает, h-pp-tokens и pp-balanced-token-sequence подвергаются макро-замене. Директива после замены будет повторно проверяться на соответствие с (4) .
new-line - Символ новой строки
h-char-sequence - Последовательность одного или более h-char s, где появление любого из следующих вызывает неопределённое поведение:
  • символ '
  • символ "
  • символ \
  • последовательность символов //
  • последовательность символов /*
h-char - Любой элемент исходного набора символов кроме новой строки и >
q-char-sequence - Последовательность одного или более q-char s, где появление любого из следующих вызывает неопределённое поведение:
  • символ '
  • символ \
  • последовательность символов //
  • последовательность символов /*
q-char - Любой элемент исходного набора символов кроме новой строки и "
pp-tokens - Последовательность одного или более токенов препроцессора
string-literal - Строковый литерал
h-pp-tokens - Последовательность одного или более токенов препроцессора кроме >
embed-parameter-sequence - Последовательность одного или более pp-parameter s. Обратите внимание, что в отличие от attribute-list , эта последовательность не разделяется запятыми.
pp-parameter - attribute-token (см.: attributes ), но состоящий из токенов препроцессора вместо токенов.
pp-balanced-token-sequence - balanced-token-sequence (см.: attributes ), но состоящий из токенов препроцессора вместо токенов

Объяснение

1) Выполняет поиск ресурса, идентифицированного h-char-sequence , способом, определяемым реализацией.
2) Выполняет поиск ресурса, идентифицированного q-char-sequence , способом, определяемым реализацией. Для (1,2) реализации обычно используют механизм, похожий на, но отличный от, пути поиска, определяемые реализацией и используемые для включения исходных файлов . Конструкция __has_embed ( __FILE__ ... появляется в одном из примеров в стандарте, предполагая, что в случае (2) , по крайней мере, ожидается поиск в директории, где находится текущий файл.
3) Препроцессинг-токены после embed в директиве обрабатываются так же, как в обычном тексте (т.е. каждое имя идентификатора, определённое в настоящее время как имя макроса, заменяется его списком замены препроцессинг-токенов). Директива, полученная после всех замен, должна соответствовать одной из двух предыдущих форм. Способ, которым последовательность препроцессинг-токенов между < и > парой препроцессинг-токенов или парой " символов объединяется в единый токен имени заголовка, определяется реализацией.
4) Ресурс, идентифицируемый h-char-sequence или q-char-sequence , ищется так, как если бы эта последовательность препроцессорных токенов была pp-tokens в синтаксисе (3) , за исключением того, что дальнейшее макроподстановка не выполняется. Если такая директива не удовлетворяет синтаксическим требованиям директивы #embed , программа является некорректной. Выражение __has_embed вычисляется в __STDC_EMBED_FOUND__ , если поиск ресурса завершается успешно, ресурс не пуст и все параметры поддерживаются, в __STDC_EMBED_EMPTY__ , если ресурс пуст и все параметры поддерживаются, и в __STDC_EMBED_NOT_FOUND__ , если поиск завершается неудачно или один из переданных параметров не поддерживается реализацией.
5) Эта форма рассматривается только в том случае, если синтаксис (4) не соответствует, и в этом случае токены препроцессора обрабатываются так же, как в обычном тексте.

В случае, если ресурс не найден или один из параметров не поддерживается реализацией, программа является некорректно сформированной.

__has_embed может раскрываться в выражениях #if и #elif . Он рассматривается как определённый макрос в #ifdef , #ifndef , #elifdef , #elifndef и defined , но не может использоваться где-либо ещё.

Ресурс имеет ширину ресурса реализации — это определенный реализацией размер в битах размещенного ресурса. Его ширина ресурса равна ширине ресурса реализации, если не изменена параметром limit . Если ширина ресурса равна 0, ресурс считается пустым. Ширина элемента внедрения равна CHAR_BIT , если не изменена параметром, определенным реализацией. Ширина ресурса должна быть кратна ширине элемента внедрения.

Расширение директивы #embed представляет собой последовательность токенов, сформированную из списка целочисленных константных выражений , описанных ниже. Группа токенов для каждого целочисленного константного выражения в списке отделяется в последовательности токенов от группы токенов для предыдущего целочисленного константного выражения в списке запятой. Последовательность не начинается и не заканчивается запятой. Если список целочисленных константных выражений пуст, последовательность токенов также пуста. Директива заменяется своим расширением и, при наличии определённых параметров embed, дополнительными или замещающими последовательностями токенов.

Значения целочисленных константных выражений в расширенной последовательности определяются реализационно-зависимым отображением данных ресурса. Значение каждого целочисленного константного выражения находится в диапазоне [ 0 , 2 embed element width ) . Если:

  1. Список целочисленных константных выражений используется для инициализации массива типа, совместимого с unsigned char , или совместимого с char , если char не может содержать отрицательные значения, и
  2. Ширина элемента embed равна CHAR_BIT ,

тогда содержимое инициализированных элементов массива таково, как если бы двоичные данные ресурса были fread в массив во время трансляции.

Реализациям рекомендуется учитывать порядок битов и байтов на этапе трансляции, а также порядок битов и байтов во время выполнения, чтобы более точно представлять двоичные данные ресурса из директивы. Это максимизирует вероятность того, что если ресурс, на который ссылаются на этапе трансляции через директиву #embed , совпадает с ресурсом, доступным во время выполнения, данные, которые, например, считываются с помощью fread или аналогичной функции в непрерывное хранилище, будут побитово идентичны массиву символьного типа, инициализированному из расширенного содержимого директивы #embed .

Параметры

Стандарт определяет параметры limit , prefix , suffix и if_empty . Любые другие параметры, присутствующие в директиве, должны быть определены реализацией, иначе программа является некорректной. Определяемые реализацией параметры embed могут изменять семантику директивы.

предел

limit( constant-expression ) (1)
__limit__( constant-expression ) (2)
**Примечание:** В данном случае весь текст внутри тегов ` `, `
`, `` и C++ специфические термины (такие как `limit`, `__limit__`, `constant-expression`) не подлежат переводу согласно инструкциям. HTML структура и форматирование полностью сохранены.

Параметр встраивания limit может встречаться не более одного раза в последовательности параметров встраивания. Он должен иметь аргумент, который должен быть целочисленным (препроцессорным) константным выражением , вычисляющимся в неотрицательное число и не содержащим токен defined . Ширина ресурса устанавливается как минимум из целочисленного константного выражения, умноженного на ширину элемента встраивания, и ширины ресурса реализации.

суффикс

suffix( pp-balanced-token-sequence  (необязательно) ) (1)
__suffix__( pp-balanced-token-sequence  (необязательно) ) (2)

Параметр встраивания suffix может встречаться не более одного раза в последовательности параметров встраивания. Он должен иметь (возможно, пустой) аргумент препроцессора. Если ресурс не пуст, содержимое параметра помещается непосредственно после раскрытия директивы. В противном случае он не оказывает никакого эффекта.

префикс

prefix( pp-balanced-token-sequence  (необязательно) ) (1)
__prefix__( pp-balanced-token-sequence  (необязательно) ) (2)

Параметр встраивания prefix может встречаться не более одного раза в последовательности параметров встраивания. Он должен иметь (возможно, пустой) аргумент препроцессора. Если ресурс не пуст, содержимое параметра помещается непосредственно перед раскрытием директивы. В противном случае он не оказывает никакого эффекта.

if_empty

if_empty( pp-balanced-token-sequence  (необязательно) ) (1)
__if_empty__( pp-balanced-token-sequence  (необязательно) ) (2)

Параметр встраивания if_empty может встречаться не более одного раза в последовательности параметров встраивания. Он должен иметь (возможно, пустой) аргумент препроцессора. Если ресурс пуст, содержимое параметра заменяет директиву. В противном случае он не оказывает никакого эффекта.

Пример

#include <stdint.h>
#include <stdio.h>
const uint8_t image_data[] =
{
#embed "image.png"
};
const char message[] =
{
#embed "message.txt" if_empty('M', 'i', 's', 's', 'i', 'n', 'g', '\n')
,'\0' // нулевой терминатор
};
void dump(const uint8_t arr[], size_t size)
{
    for (size_t i = 0; i != size; ++i)
        printf("%02X%c", arr[i], (i + 1) % 16 ? ' ' : '\n');
    puts("");
}
int main()
{
    puts("image_data[]:");
    dump(image_data, sizeof image_data);
    puts("message[]:");
    dump((const uint8_t*)message, sizeof message);
}

Возможный вывод:

image_data[]:
89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52
00 00 00 01 00 00 00 01 01 03 00 00 00 25 DB 56
...
message[]:
4D 69 73 73 69 6E 67 0A 00

Ссылки

  • Стандарт C23 (ISO/IEC 9899:2024):
  • 6.4.7 Имена заголовков (стр: 69)
  • 6.10.1 Условное включение (стр: 165-169)
  • 6.10.2 Включение бинарных ресурсов (стр: 170-177)

Смотрите также

C++ documentation для Включение ресурсов (начиная с C++26)