ClangFormatでC/C++コードを整形する

ClangFormat(クラン・フォーマット)とは、C/C++をターゲットとした強力なコード整形ツールです。eclipseやVisual Studio Codeなどで使用することができます。このようなツールを使用することで、人や環境が変わっても同じスタイルでコードを記述することができます。

本ページでは、Visual Studio Codeでの使用例を紹介します。

目次

必要なもの

Visual Studio Code

何はともあれ、本体がないことには始まりません。

C/C++

Visual Studio Codeの拡張機能です。

Visual Studio Codeの設定

STEP
下図①②の順に操作し、設定を開きます。
STEP
下図①に「c_cpp.clang_format_style」を入力した後、現れた②に「file」を入力します。
STEP
フォーマットを実行するには、右クリックして「ドキュメントのフォーマット(上側)」をクリックします。
STEP
手動でフォーマットを実行するのが面倒な場合、ファイルを保存する際に自動でフォーマットを実行させることもできます。下図①に「editor.formatonsave」を入力した後、現れた②にチェックを付けます。

Visual Studio Codeでの使用例

STEP
下記の様な構成であるとします。
src
├ main.c
├ main.h
├ ...
└ ...
STEP
ソースファイルと同じフォルダーに、「.clang-format」ファイルを置きます。
src
├ main.c
├ main.h
├ ...
└ .clang-format
STEP
Visual Studio Codeでsrcフォルダーを開きます。
STEP
ソースファイルを保存、または右クリックの「ドキュメントのフォーマット」を実行すると、コードが整形されます。

ClangFormatファイルの記述例

「.clang-format」ファイルは、下記の様に記述します。先頭行の「—」は必要なものなので削除してはいけません。

---
# アクセス修飾子のインデント
AccessModifierOffset: -2

# 引数は左揃え
AlignAfterOpenBracket: Align

# 初期化子リストを左揃え
AlignArrayOfStructures: Left

# 連続する行の位置を揃える
AlignConsecutiveAssignments: true   # "="
AlignConsecutiveDeclarations: true  # 宣言
AlignConsecutiveMacros: true        # マクロ
AlignTrailingComments: true         # コメント

# enum定数を項目毎に改行する
AllowShortEnumsOnASingleLine: false

# 短い関数を単一行にしない
AllowShortFunctionsOnASingleLine: None

# "{ }"を独立行に配置する
# "BreakBeforeBraces: Custom" の場合に有効
BraceWrapping:
  AfterClass: true              # classの後
  AfterControlStatement: false  # 制御文の後
  AfterEnum: true               # enumの後
  AfterFunction: true           # 関数の後
  AfterStruct: true             # structの後
  AfterUnion: true              # unionの後
  AfterExternBlock: false       # externの後
  BeforeCatch: false            # catchの前
  BeforeElse: false             # elseの前

# "{ }"の位置をカスタム設定する
BreakBeforeBraces: Custom

# 1行の文字数を制限する (0で無制限)
ColumnLimit: 120

# includeを名前順にソートする
IncludeBlocks: Preserve

# swicth分のcaseにインデントを設定する
IndentCaseLabels: false

# インデント
IndentWidth: 2

# ポインターの"*"、"&"は変数宣言の左に記述する
PointerAlignment: Right

# コメントは改行しない
ReflowComments: false

# キャストの後ろにスペースを入れない
SpaceAfterCStyleCast: false

# 制御文の"("の前にスペースを入れる
SpaceBeforeParens: ControlStatements

# コメントの前にスペース入れる
SpacesBeforeTrailingComments: 2

ClangFormatのスタイルオプション

ClangFormatには多数のスタイルオプションがあります。しかしそのすべてが使用している環境で動作するとは限りません。ここではVisual Studio Codeで動作確認できた範囲のものだけを抜き出しています。最新のClangFormatとは合わないところもあるかもしれませんが、参考にどうぞ。

なおClangFormatの最新バージョンの情報は下記を参照ください。

AccessModifierOffset

アクセス修飾子public、protected、privateのインデントを設定します。IndentWidthを設定している場合は、その値が基準となります。

// AccessModifierOffset: -2
// IndentWidth: 2
class Sample {
private:
  int func1(void);

public:
  int func2(void);
}

AlignAfterOpenBracket

引数の整列方法を設定します。

// AlignAfterOpenBracket: Align
someLongFunction(argument1,
                 argument2);

// AlignAfterOpenBracket: DontAlign
someLongFunction(argument1,
  argument2);

// AlignAfterOpenBracket: AlwaysBreak
someLongFunction(
  argument1, argument2);

// AlignAfterOpenBracket: BlockIndent
someLongFunction(
  argument1, argument2
);

AlignArrayOfStructures

構造体の初期化子リストを整列します。

// AlignArrayOfStructures: None
// 整列しない

// AlignArrayOfStructures: Left
struct test demo[] =
{
  {56, 23, "hello"},
  {7,  5,  "abc"  }
}; 

// AlignArrayOfStructures: Right
struct test demo[] =
{
  {56, 23, "hello"},
  { 7,  5,   "abc"}
};

AlignConsecutiveAssignments

連続する行の「=」の位置を揃えます。

// AlignConsecutiveAssignments: true
aaa  = 0;
bb   = 1;
cccc = 2;

AlignConsecutiveDeclarations

連続する行の宣言を揃えます。

// AlignConsecutiveDeclarations: true
char   sc;
int    si;
double d;

AlignConsecutiveMacros

連続する行のマクロを揃えます。

// AlignConsecutiveMacros: true
#define SHORT_NAME       42
#define EVEN_LONGER_NAME (2)
#define foo(x)           (x * x)

AlignEscapedNewlines

エスケープされた改行の、円マークの位置を揃えます。

// AlignEscapedNewlines: true  (左寄せで揃える)
#define TEST       \
  "long long test" \
  "string"

// AlignEscapedNewlines: false  (ColumnLimit位置で揃える)
#define TEST                 \
  "long long test"           \
  "string"

AlignOperands

水平方向に二項演算子と三項演算子を揃えます。

// AlignOperands: true
int aaa = bbbbbbbbbbbbbbb +
          ccccccccccccccc;

AlignTrailingComments

連続する行のコメントを揃えます。

// AlignTrailingComments: true
int a;      // comment a
int b = 2;  // comment b

AllowShortEnumsOnASingleLine

enum定数を項目毎に改行します。なおfalseに設定すると、波括弧も独立した行に表示されます。この仕様はBraceWrappingの個別設定でも回避できません。

// AllowShortEnumsOnASingleLine: true
enum { A, B } myEnum;

// AllowShortEnumsOnASingleLine: false
enum
{
  A,
  B
} myEnum;

AllowShortFunctionsOnASingleLine

短い関数を単一行にします。

// AllowShortFunctionsOnASingleLine: None
// (単一行にしない)

// AllowShortFunctionsOnASingleLine: InlineOnly
// (class内で定義された関数だけ単一行にする)
class Foo {
  void f() { foo(); }
};
void f() {
  foo();
}
void f() {
}

// AllowShortFunctionsOnASingleLine: Inline
// (class内で定義された関数と空の関数だけ単一行にする)
class Foo {
  void f() { foo(); }
};
void f() {
  foo();
}
void f() {}

// AllowShortFunctionsOnASingleLine: Empty
// (空の関数だけ単一行にする)
void f() {}
void f2() {
  bar2();
}

// AllowShortFunctionsOnASingleLine: All
// (すべて単一行にする)
class Foo {
  void f() { foo(); }
};
void f() { bar(); }

BraceWrapping

{ }の位置を個々に設定します。trueに設定すると、{ }を独立した行に記述します。なお個々に設定するためには、BreakBeforeBracesをCustomに設定する必要があります。

// インデントはスペースで入れること
BraceWrapping:
  AfterClass: true             // classの後
  AfterControlStatement: true  // 制御文の後
  AfterEnum: true              // enumの後
  AfterFunction: true          // 関数の後
  AfterNamespace: true         // namespaceの後
  AfterStruct: true            // structの後
  AfterUnion: true             // unionの後
  AfterExternBlock: true       // externの後
  BeforeCatch: true            // catchの前
  BeforeElse: true             // elseの前

BreakBeforeBraces

{ }の位置を設定します。なお下記以外にもLinux、Mozilla、Stroustrup、GNU、Webkitがありますが省略します。

// BreakBeforeBraces: Attach  (常にコンテキストに付ける)
void function(int val) {
  if (val > MAX) {
    ...
  }
  ...
}

// BreakBeforeBraces: Allman  (常に独立した行に付ける)
void function(int val)
{
  if (val > MAX)
  {
    ...
  }
  ...
}

// BreakBeforeBraces: Custom  (BraceWrappingで個々に設定する)

ColumnLimit

1行の文字数を設定します。

ColumnLimit: 120

IncludeBlocks

includeを整列(ソート)します。

// IncludeBlocks: Preserve  (連続する行を整列する)
#include <stdio.h>
#include <stdint.h>

#include "b.h"
#include "a.h"
↓
#include <stdint.h>
#include <stdio.h>

#include "a.h"
#include "b.h"

// IncludeBlocks: Merge  (離れた行も引っ付けて整列する)
#include <stdio.h>
#include <stdint.h>

#include "b.h"
#include "a.h"
↓
#include "a.h"
#include "b.h"
#include <stdint.h>
#include <stdio.h>

// IncludeBlocks: Regroup  (IncludeCategoriesの順に整列する)

IncludeCategories

「IncludeBlocks: Regroup」の整列順を設定します。

IncludeCategories:
  - Regex:           '^<.*\.h>'
    Priority:        1
  - Regex:           '^<.*'
    Priority:        2
  - Regex:           '.*'
    Priority:        3

IndentCaseLabels

caseにインデントを設定します。

// IndentCaseLabels: true
switch (val) {
  case 1:
    ...
    break;
  case 2:
    ...
    break;
  default:
    ...
}

// IndentCaseLabels: false
switch (val) {
case 1:
  ...
  break;
case 2:
  ...
  break;
default:
  ...
}

IndentWidth

インデント数を設定します。

IndentWidth: 2

PointerAlignment

ポインターの「*」や「&」の位置を揃えます。

// PointerAlignment: Left
int* p;

// PointerAlignment: Middle
int * p;

// PointerAlignment: Right
int *p;

ReflowComments

ColumnLimitを超えるコメントの、途中での改行を試みます。

// ReflowComments: true  (試みる)

// ReflowComments: false  (試みない)

SpaceAfterCStyleCast

キャストの後にスペースを入れるかを設定します。

// SpaceAfterCStyleCast: true
(int) i;

// SpaceAfterCStyleCast: false
(int)i;

SpaceBeforeAssignmentOperators

演算子の前にスペースを入れるかを設定します。

// SpaceBeforeAssignmentOperators: true
i = i + 1;

// SpaceBeforeAssignmentOperators: false
i= i + 1;

SpaceBeforeParens

開始括弧「(」の前にスペースを入れるかを設定します。

// SpaceBeforeParens: Never  (スペースを入れない)
void function(int val) {
  if(val > MAX) {
    ...
  }
}

// SpaceBeforeParens: ControlStatements  (制御文の前にはスペースを入れる)
void function(int val) {
  if (val > MAX) {
    ...
  }
}

// SpaceBeforeParens: Always  (すべてにスペースを入れる)
void function (int val) {
  if (val > MAX) {
    ...
  }
}

SpaceInEmptyParentheses

空の括弧( )内にスペースを入れるかを設定します。

// SpaceInEmptyParentheses: true
func( );

// SpaceInEmptyParentheses: false
func();

SpacesBeforeTrailingComments

コメントの前に入れるスペースの数を設定します。

// SpacesBeforeTrailingComments: 2
int name;  // 2スペース

SpacesInAngles

<>内にスペースを入れるかを設定します。

// SpacesInAngles: true
static_cast< int >(arg);

// SpacesInAngles: false
static_cast<int>(arg);

SpacesInCStyleCastParentheses

キャストの( )内にスペースを入れるかを設定します。

// SpacesInCStyleCastParentheses: true
( int )i;

// SpacesInCStyleCastParentheses: false
(int)i;

SpacesInParentheses

( )内にスペースを入れるかを設定します。

// SpacesInParentheses: true
void function( int val ) {
  if ( val > MAX ) {
    ...
  }
  ...
}

// SpacesInParentheses: false
void function(int val) {
  if (val > MAX) {
    ...
  }
  ...
}

SpacesInSquareBrackets

[ ]内にスペースを入れるかを設定します。

// SpacesInSquareBrackets: true
int a[ 5 ];

// SpacesInSquareBrackets: false
int a[5];

部分的に整形の対象外にする

初期化子リストなど、視認性をあげるため意図的に位置揃えしたいこともあります。この様な場合は「clang-format off」と「clang-format on」で囲むことで部分的に整形の対象外にすることができます。

// clang-format off
...
// clang-format on
目次