名前空間
変種
操作

バイナリリソースのインクルード (C23以降)

From cppreference.com

#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 - 1つ以上の h-char のシーケンス。以下のいずれかの出現は未定義の動作を引き起こします。
  • 文字 '
  • 文字 "
  • 文字 \
  • 文字シーケンス //
  • 文字シーケンス /*
h-char - 改行文字および > を除く ソース文字セットの任意のメンバー。
q-char-sequence - 1つ以上の q-char のシーケンス。以下のいずれかの出現は未定義の動作を引き起こします。
  • 文字 '
  • 文字 \
  • 文字シーケンス //
  • 文字シーケンス /*
q-char - 改行文字および " を除く ソース文字セットの任意のメンバー。
pp-tokens - 1つ以上の プリプロセッサートークンのシーケンス。
string-literal - 文字列リテラル
h-pp-tokens - 1つ以上の プリプロセッサートークンのシーケンス。ただし > は除きます。
embed-parameter-sequence - 1つ以上の pp-parameter のシーケンス。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) について、実装は通常、ソースファイルインクルードに使用される実装定義の検索パスと似ていますが異なるメカニズムを使用します。標準の例の1つに __has_embed(__FILE__ ... という構文が登場しており、少なくとも (2) の場合、現在のファイルが存在するディレクトリが検索されると想定されていることを示唆しています。
3) ディレクティブ内の embed の後のプリプロセッサートークンは、通常のテキストと同様に処理されます(すなわち、マクロ名として定義されている各識別子は、その置換リストのプリプロセッサートークンに置き換えられます)。すべての置換後のディレクティブは、前の2つの形式のいずれかに一致する必要があります。<> のプリプロセッサートークンペアの間、または " 文字のペアの間に配置されるプリプロセッサートークンのシーケンスが、単一のヘッダー名プリプロセッサートークンに結合される方法は、実装定義です。
4) h-char-sequence または q-char-sequence によって識別されるリソースは、そのプリプロセッサートークンシーケンスが構文 (3)pp-tokens であるかのように検索されますが、それ以上のマクロ展開は行われません。そのようなディレクティブが #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 ディレクティブの展開は、以下で説明する整数 定数式 のリストから形成されるトークンシーケンスです。リスト内の各整数定数式のトークンのグループは、リスト内の前の整数定数式のトークンのグループからカンマによってトークンシーケンスで区切られます。シーケンスはカンマで始まったり終わったりしません。整数定数式のリストが空の場合、トークンシーケンスは空です。ディレクティブは、その展開に置き換えられ、特定の埋め込みパラメータの存在により、追加または置換のトークンシーケンスが生成されます。

展開されたシーケンス内の整数定数式の値は、リソースのデータの実装定義マッピングによって決定されます。各整数定数式の値は、[02embed element width) の範囲にあります。もし

  1. 整数定数式のリストが、unsigned char 型、または char が負の値を保持できない場合は char 型と互換性のある配列を初期化するために使用され、そして
  2. 埋め込み要素幅が CHAR_BIT に等しい場合、

初期化された配列要素の内容は、翻訳時にリソースのバイナリデータが配列に fread されたかのように扱われます。

実装は、翻訳時のビット順序およびバイト順序、ならびに実行時のビット順序およびバイト順序を考慮して、ディレクティブからリソースのバイナリデータをより適切に表現することが推奨されます。これにより、翻訳時に #embed ディレクティブを介して参照されたリソースが、実行時にアクセスされるリソースと同じである場合、fread などで連続ストレージに読み込まれたデータが、#embed ディレクティブの展開された内容から初期化された文字型配列とビット単位で等しく比較される可能性が最大になります。

[編集] パラメータ

標準では、limitprefixsuffix、および if_empty パラメータが定義されています。ディレクティブに現れる他のパラメータは、実装定義であるか、プログラムが不正な形式であるかのいずれかです。実装定義の埋め込みパラメータは、ディレクティブの意味を変える可能性があります。

[編集] limit

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

limit 埋め込みパラメータは、埋め込みパラメータシーケンスに最大1回出現できます。引数が必要であり、非負の数値を評価し、defined トークンを含まない整数(プリプロセッサ)定数式である必要があります。リソース幅は、整数定数式に埋め込み要素幅を掛けた値と、実装リソース幅の最小値に設定されます。

[編集] suffix

suffix( pp-balanced-token-sequence (オプション) ) (1)
__suffix__( pp-balanced-token-sequence (オプション) ) (2)

suffix 埋め込みパラメータは、埋め込みパラメータシーケンスに最大1回出現できます。(空の場合もある)プリプロセッサ引数句が必要です。リソースが空でない場合、パラメータ句の内容はディレクティブの展開の直後に配置されます。それ以外の場合は、効果はありません。

[編集] prefix

prefix( pp-balanced-token-sequence (オプション) ) (1)
__prefix__( pp-balanced-token-sequence (オプション) ) (2)

prefix 埋め込みパラメータは、埋め込みパラメータシーケンスに最大1回出現できます。これは(空の場合もある)プリプロセッサ引数句が必要です。リソースが空でない場合、パラメータ句の内容はディレクティブの展開の直前に配置されます。それ以外の場合は、効果はありません。

[編集] if_empty

if_empty( pp-balanced-token-sequence (オプション) ) (1)
__if_empty__( pp-balanced-token-sequence (オプション) ) (2)

if_empty 埋め込みパラメータは、埋め込みパラメータシーケンスに最大1回出現できます。これは(空の場合もある)プリプロセッサ引数句が必要です。リソースが空の場合、パラメータ句の内容がディレクティブを置き換えます。それ以外の場合は、効果はありません。

[編集]

#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:2024)
  • 6.4.7 ヘッダー名 (p: 69)
  • 6.10.1 条件付きインクルード (p: 165-169)
  • 6.10.2 バイナリリソースのインクルード (p: 170-177)

[編集] 関連項目

C++ ドキュメントリソースインクルード (C++26以降)
English 日本語 中文(简体) 中文(繁體)