プログラミング言語Cの次期C2x(C23)言語仕様に追加される#embed
ディレクティブについて。外部ファイルをバイナリデータとしてプログラムに埋込む機能。
下記コードは、外部PNGファイル内容を生成プログラム中のuint8_t
型配列として埋め込む例*1 *2。C17現在は外部ツール*3を用いたビルドステップで対応しているものが、C2x以降はC言語処理系(プリプロセッサ)のみで実現される。
// C2x #include <stdint.h> // uint8_t #if __has_embed("resource/icon.png") constexpr uint8_t icon[] = { #embed "resource/icon.png" }; static_assert( (icon[0]==137 && icon[1]=='P' && icon[2]=='N' && icon[3]=='G' && icon[4]==13 && icon[5]==10 && icon[6]==26 && icon[7]==10), "invalid PNG format"); // https://www.w3.org/TR/PNG-Structure.html #else #error "icon resource not found!" #endif // icon[] == PNG圧縮画像データ列
まとめ:
#emded
ディレクティブ- 指定されたファイル(
<path>
、"path"
またはマクロ置換結果)の中身を読み取り、コンマ区切りの整数定数リストへと展開する。 - C2x標準は下記パラメータ4種類の追加指定をサポートし、また処理系定義(implementation-defined)のパラメータ定義を許容する。
limit(N)
:展開されるバイナリデータをNバイト以下に制限する。prefix(tokens)
:展開後リストの直前にtokensを配置する。バイナリデータ長=0の場合は何もしない。suffix(tokens)
:展開後リストの直後にtokensを配置する。バイナリデータ長=0の場合は何もしない。if_empty(tokens)
:バイナリデータ長=0の場合にtokensを代替配置する。それ以外は何もしない。
- 指定されたファイル(
__has_embed
式- 指定ファイルの有無、空(empty)のバイナリデータを判定するプリプロセッサ式。
- 値
0
:指定ファイルが見つからない。 - 値
1
:指定ファイルが存在し、バイナリデータは空ではない。 - 値
2
:指定ファイルが存在し、バイナリデータは空(サイズ0)。
- おまけ:C++標準に対してもP1967が提案されている。2022年9月現在の検討状況より、C++2c(C++26)以降での導入が想定される。
ホストプログラム中に外部ファイルに記述されたGLSLシェーダプログラムを埋め込む例(提案文書N3017より改変引用):
#define SHADER_TARGET "ches.glsl" extern char* merp; void init_data () { const char whl[] = { #embed SHADER_TARGET \ prefix(0xEF, 0xBB, 0xBF, ) /* UTF-8 BOM */ \ suffix(,) 0 }; // always null terminated, // contains BOM if not-empty int is_good = (sizeof(whl) == 1 && whl[0] == '\0') || (whl[0] == '\xEF' && whl[1] == '\xBB' && whl[2] == '\xBF' && whl[sizeof(whl) - 1] == '\0'); assert(is_good); strcpy(merp, whl); }
#define SHADER_TARGET "edith-impl.glsl" extern char* null_term_shader_data; void fill_in_data () { const char internal_data[] = { #embed SHADER_TARGET \ suffix(, 0) \ if_empty(0) }; strcpy(null_term_shader_data, internal_data); }
関連URL
- N3017 #embed - a scannable, tooling-friendly binary resource inclusion mechanism
- finally. #embed | The Pasture
*1:コンパイル時constexpr定数は提案文書 N3018 にてC2x導入予定。コンパイル時constexpr関数をもつC++とは異なり、C2x時点ではconstexpr定数のみが導入される。
*2:C2x仕様には(PDF)N2934が採択され、C++言語と同じ static_assert キーワードが導入される。一方でC11からある _Static_assert キーワードは廃止予定の機能(obsolescent features)とされ、新規コードでの利用は推奨されない。また例示コードでは利用していないが、(PDF)N2265の採択により理由文字列もC2xから省略可能となる。C++17以降の static_assert と同等。
*3:例えば https://linux.die.net/man/1/xxd などでバイナリファイルをC言語用の変数定義へと変換可能。