本プロジェクトでは .clang-format により、C/C++ ソースコードのフォーマットルールを定義しています。
このドキュメントでは、各オプションの設定意図とデフォルト値との違いを説明します。
BasedOnStyle: LLVM
IndentPPDirectives: BeforeHash
ColumnLimit: 120
IndentWidth: 4
AlignConsecutiveMacros: ConsecutiveIndentPPDirectives には以下の 3 つの値を指定できます。
ディレクティブをインデントしません。すべてのディレクティブが行頭に配置されます。
void func() {
if (condition) {
#ifdef DEBUG
#if defined(VERBOSE)
printf("debug\n");
#endif
#endif
}
}# は行頭に固定し、# の後にインデントを挿入します。
void func() {
if (condition) {
printf("debug\n");
}
}# ごとインデントします。ネストの深さが視覚的にわかりやすくなります。
void func() {
if (condition) {
#ifdef DEBUG
#if defined(VERBOSE)
printf("debug\n");
#endif
#endif
}
}K&R C および初期の C コンパイラでは、# は行の先頭カラムに置かなければならないという制約がありました。この制約により、プリプロセッサディレクティブを行頭に書くスタイルが定着しました。
ANSI C (C89) 以降、# の前に空白を置くことが規格上許容されるようになりましたが、慣習は変わりませんでした。
C 言語においてプリプロセッサは、コンパイラ本体とは独立したフェーズとして設計されています。プリプロセッサディレクティブはソースコードの構文構造 (関数やブロック) とは別の次元で処理されるため、コードのインデント階層に従属させないという思想がありました。
/* ディレクティブはコードの構造とは独立した存在 */
void func() {
int x = 0;
#ifdef FEATURE_A /* コードブロックの中だが行頭に書く */
x = calculate();
#else
x = default_value();
#endif
return x;
}影響力のある大規模プロジェクトがディレクティブを行頭に書くスタイルを採用しており、これが業界標準として定着しました。
clang-format のデフォルト値は LLVM のコーディングスタイルに基づいているため、None がデフォルトになっています。
デフォルトを BeforeHash や AfterHash にした場合、clang-format を既存プロジェクトに適用すると大量のプリプロセッサ行に差分が発生します。既存のコードベースの大多数がディレクティブを行頭に書くスタイルであるため、None をデフォルトにすることで既存コードへの影響を最小限に抑えています。
IndentPPDirectives オプション自体が比較的新しい機能です。
| バージョン | 追加内容 |
|---|---|
| Clang 6 (2018年3月) | IndentPPDirectives オプション導入、AfterHash をサポート |
| Clang 9 (2019年9月) | BeforeHash をサポート |
後から追加されたオプションであるため、既存のデフォルト動作 (None) を変更する理由がありませんでした。
C89 以降であれば、BeforeHash を採用することが推奨されます。その理由は以下の通りです。
AlignConsecutiveMacros は、連続する #define マクロの値やコメントの位置を縦に揃えるかどうかを制御します。デフォルト値は None (揃えない) です。
連続するマクロ定義の値の開始位置を、最長のマクロ名に合わせて揃えます。空行やコメント行で区切られたグループごとに揃えます。
#define CALC_KIND_ADD 1 /**< 加算の演算種別を表す定数。 */
#define CALC_KIND_SUBTRACT 2 /**< 減算の演算種別を表す定数。 */
#define CALC_KIND_MULTIPLY 3 /**< 乗算の演算種別を表す定数。 */
#define CALC_KIND_DIVIDE 4 /**< 除算の演算種別を表す定数。 */マクロ名の直後に値が配置され、位置は揃えられません。
#define CALC_KIND_ADD 1 /**< 加算の演算種別を表す定数。 */
#define CALC_KIND_SUBTRACT 2 /**< 減算の演算種別を表す定数。 */
#define CALC_KIND_MULTIPLY 3 /**< 乗算の演算種別を表す定数。 */
#define CALC_KIND_DIVIDE 4 /**< 除算の演算種別を表す定数。 */None がデフォルトである主な理由は、git diff への影響です。Consecutive を指定した場合、新しいマクロの追加や既存マクロのリネームにより最長のマクロ名が変わると、グループ内の全行でアライメントが再調整されます。これにより、本質的な変更が1行であっても、git diff 上では複数行の変更として表示されます。
/* CALC_KIND_MULTIPLICATION を追加した場合の差分 */
-#define CALC_KIND_ADD 1
-#define CALC_KIND_SUBTRACT 2
-#define CALC_KIND_MULTIPLY 3
-#define CALC_KIND_DIVIDE 4
+#define CALC_KIND_ADD 1
+#define CALC_KIND_SUBTRACT 2
+#define CALC_KIND_MULTIPLY 3
+#define CALC_KIND_DIVIDE 4
+#define CALC_KIND_MULTIPLICATION 5