Namespaces
Variants

Binary resource inclusion (since C23)

From cppreference.net

#embed est une directive de préprocesseur permettant d'inclure des ressources (binaires) dans la compilation, où une ressource est définie comme une source de données accessible depuis l'environnement de traduction.

Table des matières

Syntaxe

#embed < h-char-sequence > embed-parameter-sequence  (optionnel) new-line (1)
#embed " q-char-sequence " embed-parameter-sequence  (optionnel) new-line (2)
#embed pp-tokens new-line (3)
__has_embed ( " q-char-sequence " embed-parameter-sequence  (optionnel) )
__has_embed ( < h-char-sequence > embed-parameter-sequence  (optionnel) )
(4)
__has_embed ( string-literal pp-balanced-token-sequence  (optionnel) )
__has_embed ( < h-pp-tokens > pp-balanced-token-sequence  (optionnel) )
(5)
1) Recherche une ressource identifiée de manière unique par h-char-sequence et remplace la directive par une liste d'entiers séparés par des virgules correspondant aux données de la ressource.
2) Recherche une ressource identifiée par q-char-sequence et remplace la directive par une liste d'entiers correspondant aux données de la ressource. Peut revenir à (1) .
3) Si ni (1) ni (2) ne correspondent, pp-tokens subiront un remplacement de macro. La directive après remplacement sera tentée de correspondre avec (1) ou (2) à nouveau.
4) Vérifie si une ressource est disponible pour l'intégration, si elle est vide ou non et si les paramètres transmis sont pris en charge par l'implémentation.
5) Si (4) n'est pas satisfaite, h-pp-tokens et pp-balanced-token-sequence subiront un remplacement de macro. La directive après remplacement sera tentée d'être mise en correspondance avec (4) à nouveau.
new-line - Le caractère de nouvelle ligne
h-char-sequence - Une séquence d'un ou plusieurs h-char s, où l'apparition de l'un des éléments suivants provoque un comportement indéfini :
  • le caractère '
  • le caractère "
  • le caractère \
  • la séquence de caractères //
  • la séquence de caractères /*
h-char - Tout membre du jeu de caractères source sauf le caractère de nouvelle ligne et >
q-char-sequence - Une séquence d'un ou plusieurs q-char s, où l'apparition de l'un des éléments suivants provoque un comportement indéfini :
  • le caractère '
  • le caractère \
  • la séquence de caractères //
  • la séquence de caractères /*
q-char - Tout membre du jeu de caractères source sauf le caractère de nouvelle ligne et "
pp-tokens - Une séquence d'un ou plusieurs jetons de prétraitement
string-literal - Un littéral de chaîne
h-pp-tokens - Une séquence d'un ou plusieurs jetons de prétraitement sauf >
embed-parameter-sequence - Une séquence d'un ou plusieurs pp-parameter s. Notez que contrairement à une attribute-list , cette séquence n'est pas séparée par des virgules.
pp-parameter - Un attribute-token (voir : attributs ) mais composé de jetons de prétraitement au lieu de jetons.
pp-balanced-token-sequence - Une balanced-token-sequence (voir : attributs ) mais composée de jetons de prétraitement au lieu de jetons

Explication

1) Recherche la ressource identifiée par h-char-sequence de manière définie par l'implémentation.
2) Recherche la ressource identifiée par q-char-sequence de manière définie par l'implémentation. Pour (1,2) , les implémentations utilisent généralement un mécanisme similaire mais distinct des chemins de recherche définis par l'implémentation utilisés pour l'inclusion de fichiers source . La construction __has_embed ( __FILE__ ... apparaît dans l'un des exemples de la norme, suggérant, au moins dans le cas (2) , que le répertoire où se trouve le fichier courant est censé être recherché.
3) Les jetons de prétraitement après embed dans la directive sont traités comme dans le texte normal (c'est-à-dire que chaque identifiant actuellement défini comme nom de macro est remplacé par sa liste de remplacement de jetons de prétraitement). La directive résultant après tous les remplacements doit correspondre à l'une des deux formes précédentes. La méthode par laquelle une séquence de jetons de prétraitement entre < et > ou une paire de caractères " est combinée en un seul jeton de prétraitement de nom d'en-tête est définie par l'implémentation.
4) La ressource identifiée par h-char-sequence ou q-char-sequence est recherchée comme si cette séquence de tokens de prétraitement était les pp-tokens dans la syntaxe (3) , à l'exception qu'aucune expansion de macro supplémentaire n'est effectuée. Si une telle directive ne satisfait pas les exigences syntaxiques d'une directive #embed , le programme est mal formé. L'expression __has_embed prend la valeur __STDC_EMBED_FOUND__ si la recherche de la ressource réussit, que la ressource est non vide et que tous les paramètres sont pris en charge, la valeur __STDC_EMBED_EMPTY__ si la ressource est vide et que tous les paramètres sont pris en charge, et la valeur __STDC_EMBED_NOT_FOUND__ si la recherche échoue ou si l'un des paramètres transmis n'est pas pris en charge par l'implémentation.
5) Cette forme n'est considérée que si la syntaxe (4) ne correspond pas, auquel cas les jetons de prétraitement sont traités comme dans le texte normal.

Dans le cas où la ressource n'est pas trouvée ou si l'un des paramètres n'est pas pris en charge par l'implémentation, le programme est mal formé.

__has_embed peut être développé dans l'expression de #if et #elif . Il est traité comme une macro définie par #ifdef , #ifndef , #elifdef , #elifndef et defined mais ne peut pas être utilisé ailleurs.

Une ressource possède une largeur de ressource d'implémentation qui est la taille en bits définie par l'implémentation de la ressource localisée. Sa largeur de ressource est la largeur de ressource d'implémentation sauf si modifiée par un paramètre limit . Si la largeur de ressource est 0, la ressource est considérée comme vide. La largeur d'élément d'incorporation est égale à CHAR_BIT sauf si modifiée par un paramètre défini par l'implémentation. La largeur de ressource doit être divisible par la largeur d'élément d'incorporation.

L'expansion d'une directive #embed est une séquence de jetons formée à partir de la liste d' expressions constantes entières décrite ci-dessous. Le groupe de jetons pour chaque expression constante entière dans la liste est séparé dans la séquence de jetons du groupe de jetons pour l'expression constante entière précédente dans la liste par une virgule. La séquence ne commence ni ne se termine par une virgule. Si la liste d'expressions constantes entières est vide, la séquence de jetons est vide. La directive est remplacée par son expansion et, avec la présence de certains paramètres d'embed, des séquences de jetons supplémentaires ou de remplacement.

Les valeurs des expressions constantes entières dans la séquence développée sont déterminées par un mappage défini par l'implémentation des données de la ressource. La valeur de chaque expression constante entière se situe dans l'intervalle [ 0 , 2 embed element width ) . Si :

  1. La liste d'expressions constantes entières est utilisée pour initialiser un tableau d'un type compatible avec unsigned char , ou compatible avec char si char ne peut pas contenir de valeurs négatives, et
  2. La largeur de l'élément embed est égale à CHAR_BIT ,

alors le contenu des éléments initialisés du tableau est comme si les données binaires de la ressource étaient fread dans le tableau au moment de la traduction.

Les implémentations sont encouragées à prendre en compte l'ordre des bits et des octets au moment de la traduction ainsi que l'ordre des bits et des octets au moment de l'exécution pour représenter plus adéquatement les données binaires de la ressource à partir de la directive. Cela maximise la probabilité que, si la ressource référencée au moment de la traduction via la directive #embed est la même que celle accédée par des moyens au moment de l'exécution, les données qui sont par exemple lues par fread ou similaire dans un stockage contigu seront comparées bit à bit égales à un tableau de type caractère initialisé à partir du contenu développé de la directive #embed .

Paramètres

La norme définit les paramètres limit , prefix , suffix et if_empty . Tout autre paramètre apparaissant dans la directive doit être défini par l'implémentation, sinon le programme est mal formé. Les paramètres d'incorporation définis par l'implémentation peuvent modifier la sémantique de la directive.

limite

limit( expression-constante ) (1)
__limit__( expression-constante ) (2)

Le paramètre d'intégration limit ne peut apparaître qu'une seule fois dans la séquence de paramètres d'intégration. Il doit avoir un argument, qui doit être une expression constante (préprocesseur) constante qui évalue un nombre non négatif et ne contient pas le jeton defined . La largeur de ressource est définie au minimum de l'expression constante entière multipliée par la largeur de l'élément d'intégration et la largeur de ressource d'implémentation.

suffixe

suffix( séquence-de-jetons-pp-équilibrée  (optionnel) ) (1)
__suffix__( séquence-de-jetons-pp-équilibrée  (optionnel) ) (2)

Le paramètre d'intégration suffix ne peut apparaître qu'une seule fois au maximum dans la séquence de paramètres d'intégration. Il doit avoir une clause d'argument de préprocesseur (éventuellement vide). Si la ressource n'est pas vide, le contenu de la clause de paramètre est placé immédiatement après l'expansion de la directive. Sinon, il n'a aucun effet.

préfixe

prefix( séquence-de-jetons-équilibrés-pp  (optionnel) ) (1)
__prefix__( séquence-de-jetons-équilibrés-pp  (optionnel) ) (2)

Le paramètre d'intégration prefix ne peut apparaître qu'une seule fois dans la séquence de paramètres d'intégration. Il doit avoir une clause d'argument de préprocesseur (éventuellement vide). Si la ressource n'est pas vide, le contenu de la clause de paramètre est placé immédiatement avant l'expansion de la directive. Sinon, il n'a aucun effet.

if_empty

if_empty( séquence-de-jetons-équilibrés-pp  (optionnel) ) (1)
__if_empty__( séquence-de-jetons-équilibrés-pp  (optionnel) ) (2)

Le paramètre d'intégration if_empty ne peut apparaître qu'une seule fois dans la séquence de paramètres d'intégration. Il doit avoir une clause d'argument de préprocesseur (éventuellement vide). Si la ressource est vide, le contenu de la clause de paramètre remplace la directive. Sinon, il n'a aucun effet.

Exemple

#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' // terminateur nul
};
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);
}

Sortie possible :

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

Références

  • Norme C23 (ISO/CEI 9899:2024) :
  • 6.4.7 Noms d'en-tête (p: 69)
  • 6.10.1 Inclusion conditionnelle (p: 165-169)
  • 6.10.2 Inclusion de ressources binaires (p: 170-177)

Voir aussi

Documentation C++ pour Inclusion de ressources (depuis C++26)