---
title: Cプリプロセッサの話盛り合わせ
tags: 
author: [dechimal](https://www.docswell.com/user/dechimal)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/VJN398M1J8.jpg?width=480
description: Cプリプロセッサの話盛り合わせ by dechimal
published: December 20, 25
canonical: https://www.docswell.com/s/dechimal/Z37XGM-cpp-talk-2025-12-19
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/VJN398M1J8.jpg)

Cプリプロセッサの話
盛り合わせ
�/��


# Page. 2

![Page Image](https://bcdn.docswell.com/page/YE992KNYE3.jpg)

�. #elifdef
�/��


# Page. 3

![Page Image](https://bcdn.docswell.com/page/GE895RKK7D.jpg)

�. #elifdef
• C++��から追加された⾮常に⾼度で先進的な複合機能
• #elif + #ifdef
�/��


# Page. 4

![Page Image](https://bcdn.docswell.com/page/LELWYKZPJR.jpg)

�. #elifdef
• C++��から追加された⾮常に⾼度で先進的な複合機能
• #elif + #ifdef
• 例:
#ifdef ENABLE_HOGE
# include &quot;hoge.hpp&quot;
#elifdef ENABLE_FUGA // cf. #elif defined(ENABLE_FUGA)
# include &quot;fuga.hpp&quot;
#endif
�/��


# Page. 5

![Page Image](https://bcdn.docswell.com/page/4JM9N2V2EW.jpg)

�. #elifndef
�/��


# Page. 6

![Page Image](https://bcdn.docswell.com/page/PJRGDM25E9.jpg)

�. #elifndef
• C++��から追加された⾮常に⾼度で先進的な複合機能 その2
• #elif + #ifndef
�/��


# Page. 7

![Page Image](https://bcdn.docswell.com/page/PEXX1VDXEX.jpg)

�. #elifndef
• C++��から追加された⾮常に⾼度で先進的な複合機能 その2
• #elif + #ifndef
• 例: 省略
�/��


# Page. 8

![Page Image](https://bcdn.docswell.com/page/3EKW2QX9ED.jpg)

3. そのdefined、不要では？
�/��


# Page. 9

![Page Image](https://bcdn.docswell.com/page/L7314P59J5.jpg)

3. そのdefined、不要では？
#if defined ENABLE_HOGE
# if ENABLE_HOGE
#
include &quot;hoge.hpp&quot;
# endif
#endif
例: あるオプション機能の有効・無効を制御するためのマクロ
ENABLE_HOGE で分岐する
• ENABLE_HOGE が #define されていない
→ 無効
• 0 以外の整数として #define されている
→ 有効
• 空、もしくは数値と解釈できないトークンとして #define され
ている
→ コンパイルエラー
�/��


# Page. 10

![Page Image](https://bcdn.docswell.com/page/87DXQLD8EG.jpg)

3. そのdefined、不要では？
#if ENABLE_HOGE
# include &quot;hoge.hpp&quot;
#endif
↑これでよい
��/��


# Page. 11

![Page Image](https://bcdn.docswell.com/page/VJPPL2XWJ8.jpg)

3. そのdefined、不要では？
#if ENABLE_HOGE
# include &quot;hoge.hpp&quot;
#endif
↑これでよい
• #if には「最後まで展開した結果、 #define されていない識別
⼦が現われたら0として扱う」という仕様がある。
• なので、「 #define されている、かつ0でない」やその否定
「 #define されていない、または0である」の場合は単に
ENABLE_HOGE (否定の場合は !ENABLE_HOGE ) とすればよい。
��/��


# Page. 12

![Page Image](https://bcdn.docswell.com/page/2EV2QDL9EQ.jpg)

�. #embed
��/��


# Page. 13

![Page Image](https://bcdn.docswell.com/page/57GRWYX4EL.jpg)

�. #embed
// a.cpp
char const data[] = {
# embed &quot;fox.txt&quot;
};
// fox.txt
the quick brown fox
ファイルの内容をコンマ区切りの整数トークン列として取り込
む機能
��/��


# Page. 14

![Page Image](https://bcdn.docswell.com/page/4EQV3M8RJP.jpg)

�. #embed
// a.cpp
char const data[] = {
116, 104, 101, 32, 113, …
//&#039;t&#039;, &#039;h&#039;, &#039;e&#039;, SP, &#039;q&#039;,
};
⼤体こういう感じになる。(テキストファイルでなくとも可)
��/��


# Page. 15

![Page Image](https://bcdn.docswell.com/page/KJ4M1V2QE1.jpg)

�. #embed
先の例で作った data を std::print で表⽰する。
std::println(&quot;{}&quot;, data);
結果
Segmentation Fault
��/��


# Page. 16

![Page Image](https://bcdn.docswell.com/page/LE18G3ML7G.jpg)

YOU DIED
��/��


# Page. 17

![Page Image](https://bcdn.docswell.com/page/GEWZKP3QE2.jpg)

�. embed
Q. なぜ？
A. dataはヌル終端でない。
��/��


# Page. 18

![Page Image](https://bcdn.docswell.com/page/47Z1ZKV3J3.jpg)

�. #embed
Q. どうするの？
A. #embed にオプションを追加する。
char const data[] = {
# embed &quot;fox.txt&quot; suffix(,)
&#039;\0&#039;
};
suffix(TOKENS) は、埋め込むデータが空でない場合、データ末尾
に TOKENS を置く。(例では , が置かれる)
��/��


# Page. 19

![Page Image](https://bcdn.docswell.com/page/YJ6LZQ5ZEV.jpg)

�. #embed
その他のオプション
• prefix(TOKENS) : 埋め込むデータが空でない場合、データ先頭
に TOKENS を置く。
• limit(N) : Nバイトだけ埋め込む。
• if_empty(TOKENS) : 埋め込むデータが空だった場合、代わりに
TOKENS を置く。
• offset(N) : データ先頭からNバイトスキップする。
関連する機能
• __has_embed(NAME ARGS) : __has_include(NAME) の親戚。
#embed NAME ARGS が無効なとき、空データのとき、空でない
データのときを識別できる。
��/��


# Page. 20

![Page Image](https://bcdn.docswell.com/page/GJ51WRY974.jpg)

�. #embed
CPP外の類似機能
• GIMP (GNU Image Manipulation Program)、その他ドット
絵エディタ:
さっきの例のようなC⾔語の配列変数として画像を出力する
機能がある。
• std::embed()
C++��での採⽤に向けて策定中。プリプロセスではなくコン
パイラマジック関数として提供される。
でかいファイルを埋め込むにはこのほうが速くコンパイルで
きるらしい。
https://www.open-std.org/jtc�/sc��/wg��/docs/
papers/����/p����r�.html
• incbin (GNU as)
次ページ
��/��


# Page. 21

![Page Image](https://bcdn.docswell.com/page/LE314P5275.jpg)

�. #embed の類似機能: incbin
アセンブリ⾔語でオブジェクトファイルにデータを埋め込む機
能。従来から使われている。
__asm__ (R&quot;(
data:
.incbin &quot;fox.txt&quot;
.byte 0
data_size: .8byte . - data - 1
)&quot;);
extern char const data[];
extern std::size_t data_size;
std::print(&quot;size: {}\ndata: {}&quot;, data_size, (char const *)data);
出力
size: 20
data: the quick brown fox
��/��


# Page. 22

![Page Image](https://bcdn.docswell.com/page/8EDXQLD6JG.jpg)

�. __VA_OPT__()
��/��


# Page. 23

![Page Image](https://bcdn.docswell.com/page/V7PPL26Z78.jpg)

�. __VA_OPT__()
• C++��で導⼊された __VA_ARGS__ に関する補助的な機能
• __VA_OPT__(x) は x に展開されるが、 __VA_ARGS__ が空の場合は同
じく空となる。
• 主な⽤途は関数やマクロの引数リストに __VA_ARGS__ を追加す
る際、 __VA_ARGS__ が空のときだけカンマを消すこと。
��/��


# Page. 24

![Page Image](https://bcdn.docswell.com/page/2JV2QD3MJQ.jpg)

�. __VA_OPT__()
例: debug printでsource_locationを追加する
// a.cpp
#define DPRINT(fmt, ...) \
std::println(stderr, &quot;{}: &quot; fmt, \
std::source_location::current() __VA_OPT__(,) \
__VA_ARGS__ \
)
DPRINT(&quot;passed&quot;); // a.cpp:9: passed
DPRINT(&quot;x={}&quot;, 42); // a.cpp:10: x=42
注意: この例と同じことはマクロを使わずともできる
��/��


# Page. 25

![Page Image](https://bcdn.docswell.com/page/5EGRWY3XJL.jpg)

�. __VA_OPT__()
応⽤1: トークン列が空か判定する
#define PP_IS_EMPTY(...) PP_IS_EMPTY_I(__VA_ARGS__)
#define PP_IS_EMPTY_I(...) PP_IS_EMPTY_II(__VA_OPT__(0,) 1)
#define PP_IS_EMPTY_II(x, ...) x
��/��


# Page. 26

![Page Image](https://bcdn.docswell.com/page/4JQV3M557P.jpg)

�. __VA_OPT__()
応⽤2: 引数リストを数える
#define PP_SIZE(...) PP_SIZE_I(__VA_ARGS__)
#define PP_SIZE_I(...) PP_SIZE_II(__VA_ARGS__ __VA_OPT__(,) 4, 3, 2, 1, 0
#define PP_SIZE_II(_4, _3, _2, _1, _0, ...) _0
PP_SIZE() // 0
PP_SIZE(a) // 1
PP_SIZE(a, b) // 2
PP_SIZE(a, , c) // 3
��/��


# Page. 27

![Page Image](https://bcdn.docswell.com/page/K74M1V9VJ1.jpg)

�. __VA_OPT__()
性質
x , y をカッコ平衡なトークン列として、
• 分配法則: __VA_OPT__(x) __VA_OPT__(y) = __VA_OPT__(x y)
• 冪等性:
◦ __VA_ARGS__ が空のときに x も空であれば、
x = __VA_OPT__(x)
▪ 特に、 __VA_ARGS__ = __VA_OPT__(__VA_ARGS__)
◦ __VA_OPT__(x) = __VA_OPT__(__VA_OPT__(x))
��/��


# Page. 28

![Page Image](https://bcdn.docswell.com/page/LJ18G3K4EG.jpg)

�. __VA_OPT__()
応⽤3: map
f と a, b, c, … と k について f(k, a), f(k, b), f(k, c), … と展開す
るマクロ
#define PP_MAP(f, k, ...) __VA_OPT__(PP_MAP_I(f, k, __VA_ARGS__)))
#define PP_MAP_I(f, k, ...) __VA_OPT__(PP_MAP_0(f, k, __VA_ARGS__))
#define PP_MAP_0(f, k, x, ...) \
f(k, x) __VA_OPT__(PP_MAP_1(f, k, __VA_ARGS__))
#define PP_MAP_1(f, k, x, ...) \
f(k, x) __VA_OPT__(PP_MAP_2(f, k, __VA_ARGS__))
#define PP_MAP_2(f, k, x, ...) \
f(k, x) __VA_OPT__(PP_MAP_3(f, k, __VA_ARGS__))
#define PP_MAP_3(f, k, x, ...) \
f(k, x) __VA_OPT__(PP_MAP_ERROR_ITERATE_OVER)
#define F(k, x) f(k, x);
PP_MAP(F, 42, 1, 2, 3) // f(42, 1); f(42, 2); f(42, 3);
��/��


# Page. 29

![Page Image](https://bcdn.docswell.com/page/GJWZKPDZJ2.jpg)

6. 連番マクロを使わずに反復する
��/��


# Page. 30

![Page Image](https://bcdn.docswell.com/page/4EZ1ZKGL73.jpg)

6. 連番マクロを使わずに反復する
先の例のように、マクロデータ構造を反復処理するには同じ内
容の連番コピペマクロを作るのが定番。
// 再掲
#define PP_MAP(f, k, ...) __VA_OPT__(PP_MAP_I(f, k, __VA_ARGS__)))
#define PP_MAP_I(f, k, ...) __VA_OPT__(PP_MAP_0(f, k, __VA_ARGS__))
#define PP_MAP_0(f, k, x, ...) \
f(k, x) __VA_OPT__(PP_MAP_1(f, k, __VA_ARGS__))
#define PP_MAP_1(f, k, x, ...) \
f(k, x) __VA_OPT__(PP_MAP_2(f, k, __VA_ARGS__))
#define PP_MAP_2(f, k, x, ...) \
f(k, x) __VA_OPT__(PP_MAP_3(f, k, __VA_ARGS__))
#define PP_MAP_3(f, k, x, ...) \
f(k, x) __VA_OPT__(PP_MAP_ERROR_ITERATE_OVER)
��/��


# Page. 31

![Page Image](https://bcdn.docswell.com/page/Y76LZQYMJV.jpg)

6. 連番マクロを使わずに反復する
これが64個とか256個とか並んでいると⾮常に冥界で鬱くしい
コードになりがち。
• 魔クロ
• 魔黒
• 真っ黒
��/��


# Page. 32

![Page Image](https://bcdn.docswell.com/page/G751WRGQE4.jpg)

6. 連番マクロを使わずに反復する
界隈では知られている技法 (名前が分からない)
例: 列挙型と⽂字列変換関数を⽣成するマクロ DEF_ENUM
#define COLOR_LIST(def, x) \
def(x, red, 1) /* 値の指定はオプション */ \
def(x, green) \
def(x, blue)
DEF_ENUM(color, COLOR_LIST);
��/��


# Page. 33

![Page Image](https://bcdn.docswell.com/page/9J21QDYW7R.jpg)

6. 連番マクロを使わずに反復する
界隈では知られている技法 (名前が分からない)
例: 列挙型と⽂字列変換関数を⽣成するマクロ DEF_ENUM
// こんな感じになる
enum struct color { red = 1, green, blue };
std::string name_of(color _v_) {
switch (_v_) {
case color::red: return &quot;color::red&quot;;
case color::green: return &quot;color::green&quot;;
case color::blue: return &quot;color::blue&quot;;
default: throw std::invalid_argument{};
}
}
��/��


# Page. 34

![Page Image](https://bcdn.docswell.com/page/DEYZW2G97M.jpg)

6. 連番マクロを使わずに反復する
実装
#define DEF_ENUM(tname, list) \
enum struct tname { list(DEF_ENUM_MEMBER, ) }; \
std::string name_of(tname _v_) { \
switch (_v_) { \
list(DEF_ENUM_CASE, tname) \
default: throw std::invalid_argument{}; \
} \
}
#define DEF_ENUM_MEMBER(_, e, ...) \
e __VA_OPT__(= (__VA_ARGS__)),
#define DEF_ENUM_CASE(tname, e, ...) \
case tname::e: return #tname &quot;::&quot; #e;
簡単！*
* 個⼈の感想です。体感には個⼈差があります。
��/��


# Page. 35

![Page Image](https://bcdn.docswell.com/page/VJN398GDJ8.jpg)

おわり
��/��


