Binäre Ressourcen-Einbindung (seit C23)
#embed ist eine Präprozessor-Direktive zum Einbinden (binärer) Ressourcen in den Build, wobei eine Ressource als Datenquelle definiert ist, die aus der Übersetzungsumgebung zugänglich ist.
Inhalt |
[bearbeiten] Syntax
#embed < h-char-sequence > embed-parameter-sequence (optional) new-line |
(1) | ||||||||
#embed " q-char-sequence " embed-parameter-sequence (optional) new-line |
(2) | ||||||||
#embed pp-tokens new-line |
(3) | ||||||||
__has_embed ( " q-char-sequence " embed-parameter-sequence (optional) )__has_embed ( < h-char-sequence > embed-parameter-sequence (optional) ) |
(4) | ||||||||
__has_embed ( string-literal pp-balanced-token-sequence (optional) )__has_embed ( < h-pp-tokens > pp-balanced-token-sequence (optional) ) |
(5) | ||||||||
| new-line | - | Das Zeilenumbruchzeichen |
| h-char-sequence | - | Eine Sequenz von einem oder mehreren h-chars, bei denen das Auftreten eines der folgenden Elemente zu undefiniertem Verhalten führt:
|
| h-char | - | jedes Mitglied des Quellzeichen-Sets außer Zeilenumbruch und > |
| q-char-sequence | - | Eine Sequenz von einem oder mehreren q-chars, bei denen das Auftreten eines der folgenden Elemente zu undefiniertem Verhalten führt:
|
| q-char | - | jedes Mitglied des Quellzeichen-Sets außer Zeilenumbruch und " |
| pp-tokens | - | Eine Sequenz von einem oder mehreren Präprozessor-Tokens |
| string-literal | - | Ein String-Literal |
| h-pp-tokens | - | Eine Sequenz von einem oder mehreren Präprozessor-Tokens außer > |
| embed-parameter-sequence | - | Eine Sequenz von einem oder mehreren pp-parameter. Beachten Sie, dass diese Sequenz im Gegensatz zu einer attribute-list nicht kommagetrennt ist. |
| pp-parameter | - | Ein attribute-token (siehe: Attribute), aber bestehend aus Präprozessor-Tokens anstelle von Tokens. |
| pp-balanced-token-sequence | - | Eine balanced-token-sequence (siehe: Attribute), aber bestehend aus Präprozessor-Tokens anstelle von Tokens. |
[bearbeiten] Erklärung
embed in der Direktive werden genauso wie im normalen Text verarbeitet (d.h., jedes als Makroname definierte Bezeichner wird durch seine Ersetzungsliste von Präprozessor-Tokens ersetzt). Die Direktive, die nach allen Ersetzungen resultiert, muss eine der beiden vorherigen Formen erfüllen. Die Methode, mit der eine Sequenz von Präprozessor-Tokens zwischen einem < und einem > Präprozessor-Token-Paar oder einem Paar von "-Zeichen zu einem einzigen Header-Namen-Präprozessor-Token kombiniert wird, ist implementierungsdefiniert.__has__embed wird zu __STDC_EMBED_FOUND__ ausgewertet, wenn die Suche nach der Ressource erfolgreich ist, die Ressource nicht leer ist und alle Parameter unterstützt werden, zu __STDC_EMBED_EMPTY__, wenn die Ressource leer ist und alle Parameter unterstützt werden, und zu __STDC_EMBED_NOT_FOUND__, wenn die Suche fehlschlägt oder einer der übergebenen Parameter von der Implementierung nicht unterstützt wird.Wenn die Ressource nicht gefunden wird oder einer der Parameter von der Implementierung nicht unterstützt wird, ist das Programm schlecht geformt.
__has_embed kann im Ausdruck von #if und #elif expandiert werden. Es wird von #ifdef, #ifndef, #elifdef, #elifndef und defined als definiertes Makro behandelt, kann aber nirgendwo anders verwendet werden.
Eine Ressource hat eine *implementierungsdefinierte Ressourcenbreite*, die die implementierungsdefinierte Größe in Bits der gefundenen Ressource ist. Ihre *Ressourcenbreite* ist die implementierungsdefinierte Ressourcenbreite, es sei denn, sie wird durch einen limit-Parameter geändert. Wenn die Ressourcenbreite 0 ist, wird die Ressource als leer betrachtet. Die *Embed-Elementbreite* ist gleich CHAR_BIT, es sei denn, sie wird durch einen implementierungsdefinierten Parameter geändert. Die Ressourcenbreite muss durch die Embed-Elementbreite teilbar sein.
Die Expansion einer #embed-Direktive ist eine Token-Sequenz, die aus der Liste der ganzzahligen Konstanten Ausdrücke gebildet wird, die unten beschrieben sind. Die Gruppe von Tokens für jeden ganzzahligen Konstanten Ausdruck in der Liste ist in der Token-Sequenz durch ein Komma von der Gruppe von Tokens für den vorherigen ganzzahligen Konstanten Ausdruck in der Liste getrennt. Die Sequenz beginnt oder endet nicht mit einem Komma. Wenn die Liste der ganzzahligen Konstanten Ausdrücke leer ist, ist die Token-Sequenz leer. Die Direktive wird durch ihre Expansion ersetzt und, bei Vorhandensein bestimmter Embed-Parameter, um zusätzliche oder ersetzende Token-Sequenzen erweitert.
Die Werte der ganzzahligen Konstanten Ausdrücke in der erweiterten Sequenz werden durch eine implementierungsdefinierte Abbildung der Ressourcendaten bestimmt. Jeder Wert eines ganzzahligen Konstanten Ausdrucks liegt im Bereich [0, 2embed element width). Wenn
- die Liste der ganzzahligen Konstanten Ausdrücke zur Initialisierung eines Arrays eines Typs verwendet wird, der mit unsigned char kompatibel ist, oder kompatibel mit char, wenn char keine negativen Werte speichern kann, und
- die Embed-Elementbreite gleich CHAR_BIT ist,
dann sind die Inhalte der initialisierten Elemente des Arrays so, als ob die Binärdaten der Ressource zur Übersetzungszeit in das Array fread-mäßig gelesen würden.
Implementierungen werden ermutigt, Übersetzungszeit-Bit- und Byte-Reihenfolgen sowie Ausführungszeit-Bit- und Byte-Reihenfolgen zu berücksichtigen, um die Binärdaten der Ressource aus der Direktive besser darzustellen. Dies maximiert die Wahrscheinlichkeit, dass, wenn die zur Übersetzungszeit über die #embed-Direktive referenzierte Ressource dieselbe ist, die zur Laufzeit über Mittel wie fread oder ähnliches in zusammenhängenden Speicher zugegriffen wird, die Daten Bit-für-Bit mit einem Array vom Zeichentyp übereinstimmen, das aus den erweiterten Inhalten einer #embed-Direktive initialisiert wurde.
[bearbeiten] Parameter
Der Standard definiert die Parameter limit, prefix, suffix und if_empty. Jeder andere Parameter, der in der Direktive vorkommt, muss implementierungsdefiniert sein, oder das Programm ist schlecht geformt. Implementierungsdefinierte Embed-Parameter können die Semantik der Direktive ändern.
[bearbeiten] limit
limit( constant-expression ) |
(1) | ||||||||
__limit__( constant-expression ) |
(2) | ||||||||
Der limit-Embed-Parameter kann höchstens einmal in der Embed-Parametersequenz vorkommen. Er muss ein Argument haben, das ein ganzzahliger (Präprozessor) Konstanten Ausdruck sein muss, der zu einer nicht-negativen Zahl ausgewertet wird und nicht das Token defined enthält. Die Ressourcenbreite wird auf das Minimum der ganzzahligen Konstanten Ausdruck multipliziert mit der Embed-Elementbreite und der implementierungsdefinierten Ressourcenbreite gesetzt.
[bearbeiten] suffix
suffix( pp-balanced-token-sequence (optional) ) |
(1) | ||||||||
__suffix__( pp-balanced-token-sequence (optional) ) |
(2) | ||||||||
Der suffix-Embed-Parameter kann höchstens einmal in der Embed-Parametersequenz vorkommen. Er muss eine (möglicherweise leere) Präprozessor-Argumentklausel haben. Wenn die Ressource nicht leer ist, werden die Inhalte der Parameterklausel unmittelbar nach der Expansion der Direktive platziert. Andernfalls hat sie keine Auswirkung.
[bearbeiten] prefix
prefix( pp-balanced-token-sequence (optional) ) |
(1) | ||||||||
__prefix__( pp-balanced-token-sequence (optional) ) |
(2) | ||||||||
Der prefix-Embed-Parameter kann höchstens einmal in der Embed-Parametersequenz vorkommen. Er muss eine (möglicherweise leere) Präprozessor-Argumentklausel haben. Wenn die Ressource nicht leer ist, werden die Inhalte der Parameterklausel unmittelbar vor der Expansion der Direktive platziert. Andernfalls hat sie keine Auswirkung.
[bearbeiten] if_empty
if_empty( pp-balanced-token-sequence (optional) ) |
(1) | ||||||||
__if_empty__( pp-balanced-token-sequence (optional) ) |
(2) | ||||||||
Der if_empty-Embed-Parameter kann höchstens einmal in der Embed-Parametersequenz vorkommen. Er muss eine (möglicherweise leere) Präprozessor-Argumentklausel haben. Wenn die Ressource leer ist, ersetzen die Inhalte der Parameterklausel die Direktive. Andernfalls hat sie keine Auswirkung.
[bearbeiten] Beispiel
#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); }
Mögliche Ausgabe
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
[bearbeiten] Referenzen
- C23-Standard (ISO/IEC 9899:2024)
- 6.4.7 Header-Namen (S. 69)
- 6.10.1 Bedingte Einbindung (S. 165-169)
- 6.10.2 Binäre Ressourcen-Einbindung (S. 170-177)
[bearbeiten] Siehe auch
| C++ Dokumentation für Ressourcen-Einbindung (seit C++26)
|