プログラミング言語Cの次期C2x(C23)言語仕様に追加される#embedディレクティブについて。外部ファイルをバイナリデータとしてプログラムに埋込む機能。
2025-02-20追記:プログラミング言語C++においても、次期C++2c(C++26)に同機能を追加する提案文書P1967R14が採択された。*1
下記コードは、外部PNGファイル内容を生成プログラム中のuint8_t型配列として埋め込む例*2 *3。C17現在は外部ツール*4を用いたビルドステップで対応しているものが、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)。
ホストプログラム中に外部ファイルに記述された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:https://github.com/cplusplus/papers/issues/700
*2:コンパイル時constexpr定数は提案文書 N3018 にてC2x導入予定。コンパイル時constexpr関数をもつC++とは異なり、C2x時点ではconstexpr定数のみが導入される。
*3:C2x仕様には(PDF)N2934が採択され、C++言語と同じ static_assert キーワードが導入される。一方でC11からある _Static_assert キーワードは廃止予定の機能(obsolescent features)とされ、新規コードでの利用は推奨されない。また例示コードでは利用していないが、(PDF)N2265の採択により理由文字列もC2xから省略可能となる。C++17以降の static_assert と同等。
*4:例えば https://linux.die.net/man/1/xxd などでバイナリファイルをC言語用の変数定義へと変換可能。