Включение бинарных ресурсов (с C23)
#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) |
| new-line | - | Символ новой строки |
| h-char-sequence | - | Последовательность одного или более h-charов, где появление любого из следующего приводит к неопределённому поведению:
|
| h-char | - | Любой член набора символов источника с исключением новой строки и > |
| q-char-sequence | - | Последовательность одного или более q-charов, где появление любого из следующего приводит к неопределённому поведению:
|
| q-char | - | Любой член набора символов источника с исключением новой строки и " |
| pp-tokens | - | Последовательность одного или более токенов препроцессора |
| string-literal | - | Строковая литерал |
| h-pp-tokens | - | Последовательность одного или более токенов препроцессора за исключением > |
| embed-parameter-sequence | - | Последовательность одного или более pp-parameter ов. Отличие от attribute-list в том, что эта последовательность не разделена запятыми. |
| pp-parameter | - | attribute-token (см.: атрибуты), но состоящий из токенов препроцессора вместо самих токенов. |
| pp-balanced-token-sequence | - | balanced-token-sequence (см.: атрибуты), но состоящий из токенов препроцессора вместо самих токенов |
Объяснение
__has_embed(__FILE__ ... в одном из примеров стандарта предполагают, что в случае (2), по крайней мере, проверяется каталог, где находится текущий файл.embed в директиве обрабатываются так же, как и обычный текст (т.е. каждое идентификатор, в настоящее время определённое как имя макроса, заменяется его списком токенов-заменителей). Результирующая директива после всех замен должна соответствовать одной из двух предыдущих форм. Способ объединения последовательности токенов препроцессора между парой токенов < и > или парой символов " в один токен имени заголовка — определяется реализацией.__has__embed оценивается как __STDC_EMBED_FOUND__ при успешном поиске ресурса, непустом ресурсе и поддержке всех параметров, как __STDC_EMBED_EMPTY__ при пустом ресурсе и поддержке всех параметров и как __STDC_EMBED_NOT_FOUND__ при неудачном поиске или при неподдержке одного из передаваемых параметров реализацией.В случае, если ресурс не найден или один из параметров не поддерживается реализацией, программа является некорректной.
__has_embed может быть раскрыто в выражении #if и #elif. Оно обрабатывается как определённый макрос #ifdef, #ifndef, #elifdef, #elifndef и defined, но не может быть использовано в других местах.
Ресурс имеет ширину ресурса реализации, которая представляет собой определённую реализацией размер ресурса в битах. Его ширина ресурса равна ширине ресурса реализации, если не изменена параметром limit. Если ширина ресурса равна 0, ресурс считается пустым. Ширина элемента встраивания равна CHAR_BIT, если не изменена параметром, определённым реализацией. Ширина ресурса должна быть кратна ширине элемента встраивания.
Расширение директивы #embed — это последовательность токенов, образованная из списка целых константных выражений, описанных ниже. Группа токенов для каждого целого константного выражения в списке отделяется в последовательности токенов от группы токенов предыдущего целого константного выражения в списке запятой. Последовательность не начинается и не заканчивается запятой. Если список целых константных выражений пуст, последовательность токенов пуста. Директива заменяется своим расширением и, при наличии определённых параметров встраивания, дополнительными или заменяющими последовательностями токенов.
Значения целочисленных константных выражений в расширенной последовательности определяются реализацией с помощью сопоставления данных ресурса. Каждое целочисленное константное выражение имеет значение в диапазоне [0, 2ширина элемента вставки). Если:
- Список целочисленных константных выражений используется для инициализации массива типа, совместимого с
unsigned char, или совместимого сcharеслиcharне может хранить отрицательные значения, и - Ширина элемента вставки равна
CHAR_BIT,
то содержимое инициализированных элементов массива такое же, как если бы двоичные данные ресурса были fread в массив во время трансляции.
Реализации рекомендуется учитывать порядок битов и байтов во время трансляции, а также во время выполнения, чтобы точнее представить двоичные данные ресурса из директивы. Это максимизирует вероятность того, что, если ресурс, на который ссылаются во время трансляции с помощью директивы #embed, является тем же, к которому обращаются во время выполнения, данные, например, fread или аналогичные в непрерывном хранилище, будут полностью совпадать с битовым уровнем массиву символьного типа, инициализированному из расширенного содержимого директивы #embed.
Параметры
Стандарт определяет параметры limit, prefix, suffix и if_empty. Любой другой параметр, который появляется в директиве, должен быть определён реализацией, иначе программа некорректна. Определяемые реализацией параметры вставки могут изменить семантику директивы.
limit
limit( константное выражение ) | (1) | |
__limit__( константное выражение ) | (2) |
Параметр вставки limit может появиться не более одного раза в последовательности параметров вставки. Он должен иметь аргумент, который должен быть целочисленным (предпроцессорным) константным выражением, значение которого равно неотрицательному числу и не содержит токен defined. Ширина ресурса устанавливается как минимум в произведение значения целочисленного константного выражения и ширины элемента вставки, а также ширины ресурса реализации.
suffix
suffix( последовательность токенов сбалансированных предпроцессором (необязательно) ) | (1) | |
__suffix__( последовательность токенов сбалансированных предпроцессором (необязательно) ) | (2) |
Параметр вставки suffix может появиться не более одного раза в последовательности параметров вставки. Он должен иметь (возможно, пустую) секцию аргументов предпроцессора. Если ресурс не пустой, содержимое секции аргументов размещается непосредственно после расширения директивы. В противном случае, оно не оказывает влияния.
prefix
prefix( последовательность токенов сбалансированных предпроцессором (необязательно) ) | (1) | |
__prefix__( последовательность токенов сбалансированных предпроцессором (необязательно) ) | (2) |
Параметр вставки prefix может появиться не более одного раза в последовательности параметров вставки. Он должен иметь (возможно, пустую) секцию аргументов предпроцессора. Если ресурс не пустой, содержимое секции аргументов размещается непосредственно перед расширением директивы. В противном случае, оно не оказывает влияния.
if_empty
if_empty( последовательность токенов сбалансированных предпроцессором (необязательно) ) | (1) | |
__if_empty__( последовательность токенов сбалансированных предпроцессором (необязательно) ) | (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' // null terminator
};
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:2023):
- 6.4.7 Имена заголовков (стр. 69)
- 6.10.1 Условное включение (стр. 165-169)
- 6.10.2 Включение двоичных ресурсов (стр. 170-177)
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/c/preprocessor/embed