字下げスタイル(じさげスタイル)またはインデントスタイル()とは、プログラミングにおいてプログラムの構造を明らかにするために、コードのブロックの字下げをどうするかを決めたものである。本項ではC言語やそれに類似した言語を主に扱うが、他のプログラミング言語(特に括弧を使用してブロックを記述する言語)にも適用可能である。字下げスタイルはプログラミング作法の一部である。
概要 字下げは大半のプログラミング言語では必須ではない。むしろ、プログラマは他の読者、あるいは自分自身にプログラムの構造を見やすく伝えるために字下げを行う。特に字下げは、条件分岐やループといった制御構造を明示するために使われる。なお一部の言語(PythonやOccam)では、括弧やキーワードではなく字下げで構造を定義する。これはオフサイドルールと呼ばれ、字下げはコンパイラやインタプリタの解釈に影響を与え、見やすさやスタイルを超える意味を持つ。
文における中括弧の配置 字下げスタイルの主な違いは、複数の文で構成される制御の並びにおける中括弧の配置にある。以下の表は各スタイルの配置を示したもので、関数宣言における配置とは異なる場合がある。一貫性を持たせるため、各スタイルで好まれる字下げの深さに関わらず、ここでは4スペースで統一している。
括弧の配置 スタイル while (x == y) { something(); somethingelse(); } オールマン while (x == y) { something(); somethingelse(); } K&R while (x == y)
something (); somethingelse (); } GNU while (x == y)
something(); somethingelse(); } ホワイトスミス while (x == y) { something(); somethingelse(); } Horstmann while (x == y) { something() ; somethingelse()
} Haskell while (x == y) { something(); somethingelse(); } Pico while (x == y) { something(); somethingelse(); } ラトリフ while (x == y) { something(); somethingelse(); } Lisp
タブ、スペース、文字数 字下げの大きさもスタイルによって様々である。多くの初期のプログラムは字下げにタブ文字を使っていた。これは、単純であり、ソースファイルの大きさを無駄に大きくしないという利点があった。しかし同時に、定義が異なる環境でソースファイルをやり取りすると混乱が生じることがあった。例えば、UNIXのエディタでのタブ文字の長さが一般に空白文字8個分である一方、macOSでは4文字分である。そのため、最近のプログラミング向けエディタでは任意のサイズの字下げが可能で、空白文字とタブ文字を適当に混在させられることが多い。また、字下げをそもそも空白文字のみで行うこともある。
ツール 字下げスタイルやタブ文字の長さを自動的に調節するプログラムも存在する。例えば、UNIX系オペレーティングシステムによく搭載されているプログラムとして indent がある。このようなプログラムは、その作者が一般的と考えた字下げスタイルが自分の字下げスタイルに合っている場合には有効であるが、自分の字下げスタイルと違っている場合には余計に不満が出てくる場合もある。
スタイル
K&Rのスタイル K&Rスタイル (あるいは、カーネルスタイル)とは、ブライアン・カーニハンとデニス・リッチーの著書でK&Rこと『プログラミング言語C』で使われた字下げスタイルであり、C言語で一般に使われている。C11 の仕様書 ISO/IEC 9899:2011 のサンプル、UNIXカーネル、Linuxカーネルはこのスタイルでソースコードが書かれている。Objective-C、C++ などでは、それほど一般的ではない。このスタイルでは、ブロック開始の中括弧を制御文と同じ行に置き、ブロック内の文を字下げして記し、ブロックを閉じる中括弧を制御文と同じ字下げ位置に戻して記す(その行は中括弧が先頭になる)。関数はそれとは異なり、関数の定義の最初の中括弧は宣言の次の行の先頭に記され、宣言と同じ字下げレベルとなる(これは次の例で示すように、ANSI標準より前の構文のせいでもある(K&Rの初版の中のコードはこのような構文で書かれていた)。行頭の中括弧で関数本体の先頭を検出しているツール等があったため、標準化後や他のスタイルのコードでもここだけは同じにしていることも多い)。 int main(argc, argv) int argc; char *argv[]; { ... while (x == y) { something(); somethingelse(); if (some_error) do_correct(); // K&Rでは単独の文しかないブロックには中括弧を付けていない。 else continue_as_usual();
finalthing(); ... }
プログラミング言語C は、プログラミングにこのスタイルを推奨しているわけではない。次で述べるように、スタイルを選んだら一貫して使うように、とのみ述べている。単に同書に印刷されているプログラムリストがこのスタイルであるというだけであり、書籍としてのレイアウト上の都合による点がある(特に波括弧の手前に改行を入れない点など)とも言われる。
同書自身による注意をここに引用する:
これは字下げスタイルにこだわる人々への戒めでもある。著者の1人デニス・リッチーはC言語の設計開発者でもあるが、彼がこの字下げスタイルの支持者というわけでもない。
初期のC言語では、引数の型は行を分けて書かなければならなかった (関数ヘッダの直後)。
/* ISO標準化以前の関数プロトタイプ宣言がなかった時代の、オリジナルのC言語で使われていたスタイル */ int main(argc, argv) int argc; char *argv[]; { ... }
1TBS(OTBS) "The One True Brace Style"(真の中括弧スタイル)(1TBS あるいは OTBSと略される)はK&Rと非常に類似している。
このスタイルの支持者によれば、ブロック開始の中括弧は新たな行に置く必要はなく、最後の中括弧は概念的に対応する文と同じ位置まで上げるのだという。このスタイルの欠点は、ブロックの最後の中括弧が行を新たに必要とする点であるが、if/else や do/while ではこれが部分的に改善される。
if (x < 0) { printf("Negative"); negative(x); } else { printf("Positive"); positive(x); }
このスタイルのソースコードはブロック開始の中括弧を探すのが困難と言われるが、字下げが始まった位置は見れば明らかなので、その上の行の最後に中括弧があることは明らかである。
このスタイルができた当時、端末の行数はわずか24行であったため、ブロック開始の中括弧に1行を割くことで見える範囲が狭まることを嫌ったと考えられる。上の例でも明らかなように、if...else if...[etc.]...else といったコードでは、中括弧ごとに新たな行を消費するよりも多くの内容が少ない行数で表示できる。
AppleのXcodeはこのスタイルをデフォルトで使っている。
Linuxカーネル LinuxカーネルのスタイルはK&Rスタイルから若干異なっており、Linuxカーネル全体で一貫して使われていることでよく知られている。このスタイルについての詳細はここで詳しく示されているkernel.org.リーナス・トーバルズは全てのコントリビューターがこれに従うよう強く推奨している。このスタイルはK&Rから多くの要素を引き継いでいる。
このカーネルスタイルはタブを字下げに使い、タブ幅は8文字とされる。関数ヘッダに続く行の先頭で関数の括弧を開く。それ以外の場合は対応する文と同じ行の末尾で括弧を開く。switch文のラベルは囲んでいるブロックに合わせる (字下げのレベルは1段階のみ)。複合文 (if、while、do-whileなど) が単一の文を持つ場合は括弧を付けない。ただしif-elseのいずれか片方のブロックが括弧を必要とする場合は、両方のブロックを括弧で囲む。1行の長さは80文字に制限されるが、現在は100文字まで緩和されており、元の制限を守ることは今でも推奨されている。
Linuxカーネルスタイルでは「もし条件文の片方が単一の文である場合は、両方に括弧を使う」とされている。
int power(int x, int y) { int result;
if (y < 0) { result = 0; } else { result = 1; while (y-- > 0) result *= x;
return result; }
強制括弧 スコープ内に1文しかない場合でも常に括弧を付けるべきだと主張する人もいる。1文だけであってもif、else、whileに常に括弧を付けることで、コードのどこかに新しい行を挿入しても常に安全である(挿入によって実行の流れがソースコードの字下げ一致しなくなることがない)。
代償として、各ブロックの最後に余分な1行が必要となる。
Java/ECMAScript Java言語ではサン・マイクロシステムズが1995年(最終改訂は1999年4月20日)に発表した公式のコーディング規約「Code Conventions for the Java Programming Language」Code Conventions for the Java Programming Language: Contentsに沿って書かれることが多い。これは、K&Rスタイルをベースに、クラス定義やメソッド定義の最初の中括弧を次の行に置いたりしない物である。また、ActionScriptやJavaScriptといったECMAScript派生言語でも一般的にJava言語コーディング規約に類似した書き方がされることが多い。 class Test { public static void main(String[] args) { if (args.length > 0) { } else {
ストロヴストルップ ストロヴストルップ・スタイルはビャーネ・ストロヴストルップがC++で使ったK&Rスタイルで、ストラウストラップのプログラミング入門 C++によるプログラミングの原則と実践やThe C++ Programming Languageといった彼の著書で使われている。
前述のスタイルと異なり、cuddled else (elseの前後に}と{を置くスタイル) を使わない。したがってストロヴストルップ式では次のようになる。
if (x < 0) { puts("Negative"); negative(x);
else { puts("Non-negative"); nonnegative(x);
ストロヴストルップはK&Rスタイルをクラスに拡張しており、次のように表記される。
class Vector { public: Vector(int s) :elem(new double[s]), sz(s) { } // Vectorのコンストラクタ double& operator[](int i) { return elem[i]; } // インデクサ int size() { return sz; } private: double * elem; // 要素へのポインタ int sz; // 要素数
ストロヴストルップはとを字下げしない。またこのスタイルでは、関数の次の行で括弧を開く一方で、クラスについてはクラス名と同じ行の中で括弧を開いている。
ストロヴストルップ式では短い関数を1行にまとめてしまうことを許している。ストロヴストルップのスタイルはEmacsで利用できる名前付き字下げスタイルである。ストロヴストルップはC++でもK&R由来のスタイルを使うことを推奨しており、彼の最近の著書であるC++ Core Guidelinesで言及されている。
BSD/KNFスタイル Kernel Normal Form とも呼ばれるスタイルで、BSD系オペレーティングシステムでよく使われている。主にカーネルコードで使われているが、ユーザーランドのコードでもよく使われている。これは基本的にはベル研究所のUnixバージョン6と7で用いられた、きちんと文章化されたK&Rである。
SunOSのカーネルとユーザーランドでも同様のスタイルが使われる。KNFと同様に、AT&Tのスタイル仕様書に基づいており、ビル・ジョイNormal Formと呼ばれることがある。SunOSのガイドラインは1996年に発行されており、ANSI Cについての言及がある。ソースコードの字下げが正しいかどうかはビル・シャノンが開発したcstyleで調べることができる。
ハードタブ(viでは ts)は一般に8文字ぶんの幅だが、ソフトタブはその補助として定義され(vi では sw)、通常4文字幅とされている。
ハードタブはブロックを示すのに使われ、ソフトタブは文が1行に収まらずに折り返さなければならないときに使われる。
さらに言えば、関数呼び出しでは括弧の前に空白を置かないが、C言語の構文 if、while、do、switch、return は括弧の前に空白を置く(return 文で値を返すとき括弧を使用)。
以下はその例である: while (x == y) { something(); somethingelse(); } finalthing();
if (data != NULL && res > 0) { if (!JS_DefineProperty(cx, o, "data", STRING_TO_JSVAL( JS_NewStringCopyN(cx, data, res)), NULL, NULL, JSPROP_ENUMERATE)) { QUEUE_EXCEPTION("Internal error!"); goto err;
PQfreemem(data); } else { if (!JS_DefineProperty(cx, o, "data", OBJECT_TO_JSVAL(NULL), NULL, NULL, JSPROP_ENUMERATE)) { QUEUE_EXCEPTION("Internal error!"); goto err;
static JSBool pgresult_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { QUEUE_EXCEPTION("PGresult class not user-instanciable");
return JS_FALSE; }
BSD/オールマンのスタイル BSD/オールマン・スタイル (Allman style) もよく使われる。これはBSDで数多くのユーティリティを開発したエリック・オールマンの名が由来である (上述のBSD KNFスタイルと混同されないようにされたし)。
このスタイルでは、制御文の後の中括弧を次の行に置き、制御文と同じ字下げ位置とする。ブロック内の文は次のレベルに字下げされる。
while (x == y) { something(); somethingelse(); } finalthing();
これはPascalやTransact-SQLの標準的な字下げに似ていて、中括弧が "begin" や "end" といったキーワードと同じように扱われている。
(* オールマン式の字下げをPascalで記述した場合の例 *) procedure dosomething(x, y: Integer); begin while x = y do begin something(); somethingelse(); end; end;
このスタイルの利点は、ブロックの前後が中括弧しかないほとんど空白の行で囲まれているため、非常にわかりやすい点である。また、対応する中括弧が同じ字下げ位置に必ず来るので、その対応も目で追いやすい。またブロックの形がコードのブロックと、対応する制御文を区別する。制御文やコードブロックをコメント化するなど、コードのリファクタリングをする際に括弧の位置によるエラーを引き起こしにくくなる。また括弧の配置は一番外側の関数定義の配置と一貫性がある。
例えば以下コードは文法的に正しい。
// while (x == y) { something(); somethingelse(); }
これも同様。
// for (int i=0; i < x; i++) // while (x == y) if (x == y) { something(); somethingelse(); }
さらに条件付きコンパイルでも使える。
int c; #ifdef HAS_GETCH while ((c = getch()) != EOF) #else while ((c = getchar()) != EOF) #endif
do_something(c);
このスタイルは、制御文とブロックを分離することで可読性を向上させることを目的としており、一度に表示できるコードの量は二の次となっている。
Microsoft Visual Studio(Microsoft Visual C++)は、このスタイルをデフォルトで使っている。
Allman-8 Allman-8はK&Rの亜種であるLinuxカーネルの80文字制限と8文字のタブ記号に従ったもので、アメリカの教育現場でよく使われている。このスタイルはプロジェクター使用時の可読性を向上させる。また字下げ幅と桁数制限により、深すぎるネストが一目でわかるようになる。こうした利点は初心者や学習者が複雑なコードを自然に避けるように仕向けるのに役立つ。
C# C#言語について、マイクロソフトは「C# のコーディング規則」C# のコーディング規則 - C# プログラミング ガイド | Microsoft Docsを公開しており、このレイアウト規則はBSD/オールマンのスタイルに基づいている。 if ((val1 > val2) && (val1 > val3)) { something(); }
ホワイトスミスのスタイル ホワイトスミス・スタイルはあまり有名ではない。ウィッシャート・スタイルとも呼ばれ、もともとは世界初の商用Cコンパイラであるホワイトスミス・コンパイラで、ドキュメントに使われていた。またこれは初期のWindows業界でもよく使われ、Programmer's Guide to Windows (Durant、Carlson、Yao共著)、Programming Windows (Petzold著)、Windows 3.0 Power Programming Techniques (Norton、Yao共著)などのような人気のWindowsプログラミング書籍でも使われた。
このスタイルでは制御文の後の中括弧を次の行に置くが、このときに字下げする。ブロック内の文は中括弧と同じ字下げレベルに書かれる。
while (x == y)
something(); somethingelse();
finalthing();
このスタイルの利点はBSD/オールマン・スタイルと同じで、ブロックと制御文が明確に分離される点である。また、中括弧とその中の文を同じ字下げレベルにすることで概念的にこれらが1つの文と同じであることを強調する。さらに、中括弧が文法的には while 文などの一部ではなく、複合文の一部であることも強調している。
欠点は中括弧が目立たない点である。ただし、中括弧だけで1つの行となっているため、目立つか目立たないかは意見の分かれるところでもある。
if (data != NULL && res > 0)
if (!JS_DefineProperty(cx, o, "data", STRING_TO_JSVAL(JS_NewStringCopyN(cx, data, res)), NULL, NULL, JSPROP_ENUMERATE))
QUEUE_EXCEPTION("Internal error!"); goto err;
PQfreemem(data);
else if (!JS_DefineProperty(cx, o, "data", OBJECT_TO_JSVAL(NULL), NULL, NULL, JSPROP_ENUMERATE))
QUEUE_EXCEPTION("Internal error!"); goto err;
else ifは文として扱われ、プリプロセッサの#elifと統一感がある。
GNUスタイル BSD/オールマンやホワイトスミス・スタイルと同様、GNUスタイルでも中括弧だけで行を構成する。中括弧は空白2個ぶん字下げされ、その中の文はさらに空白2個ぶん字下げされる。ただし関数定義では字下げしない。
リチャード・ストールマンが広めたスタイルであり、LISPのコードを書いた経験がベースにあると考えられる。Lispではブロックに相当するもの (progn) はファーストクラスのデータ要素であり、新たな字下げレベルを与えることで強調できるが、Cではブロックは単なる構文である。このスタイルは1960 - 1970年代にあるALGOLやXPLの書籍にも見られるR. Baumann, M. Feliciano, F. L. Bauer, and K. Samuelson, Introduction to Algol, 1964, https://archive.org/details/introductiontoal00baumW. M. McKeeman, J. J. Horning, and D. B. Wortman, A Compiler Generator, 1970, https://archive.org/details/compilergenerato00mcke。字下げとは直接関係ないが、GNUスタイルでは関数呼び出しの括弧の前にも空白を置く。
static char * concat (char *s1, char *s2) { while (x == y)
something (); somethingelse ();
finalthing (); }
利点はBSD/オールマンやホワイトスミスと同様で、かつホワイトスミスの欠点とされた「中括弧が目立たない」という問題にも対処している。
GNU EmacsエディタやGNUのindentコマンドでは、デフォルトでこのスタイルでの字下げを行う。GNU関係者はほぼ全てこのスタイルを使っているが、GNU以外でも一部で使われている。
GNU Emacs を使わない場合や、類似のカスタマイズ可能なエディタを使えない場合、エディタによる自動字下げではこのスタイルはなかなか対応できない。
ホルストマン・スタイル 1997年にケイ・S・ホルストマンが執筆したComputing Concepts with C++ Essentialsではオールマン・スタイルの亜種が使われており、ブロックの頭で括弧を開き、同じ行に最初の文を置いている。このスタイルはイェンセンとルイスが書いたPascal User Manual and Reportでも使われている。
while (x == y) { something(); somethingelse(); //... if (x < 0) { printf("Negative"); negative(x);
else { printf("Non-negative"); nonnegative(x);
finalthing();
このスタイルではオールマンの長所である読みやすさを重視した括弧の縦の並びを維持し、ブロックを識別しやすくしつつ、K&Rスタイルのような1行を節約できる一挙両得のスタイルである。しかし2003年の改版では全面的にオールマン・スタイルが採用されたHorstmann Style Guide。
Picoスタイル Picoという言語で、その開発者も一般に使っているスタイルは、これまでに説明したどのスタイルとも異なっている。Pico には return 文がなく、文の終わりを示す記号としてではなく文と文の分離記号としてセミコロンが使われていることから、次のようなスタイルが生まれた:
stuff(n): { x: 3 * n; y: doStuff(x); y + x }
その利点と欠点は、画面表示量を重視するK&Rスタイルに近い。また、どちらの中括弧も独立した行になっていないという点でK&Rスタイルよりも一貫性があるとも言える。
ラトリフのスタイル C・ウェイン・ラトリフは著書Programmers at Workで以下のスタイルについて書いている。スタイルは1TBSとほぼ同じだが、閉じ括弧はネストしたブロックの字下げと同じ位置になる。ラトリフはdBase-IIと-III、4GLなどの人気ソフトのオリジナル版のプログラマ。このスタイルは元々はDECで仕様化されていた。バナー式とも呼ばれる。ブロックのヘッダ部だけを字下げレベルで特別に目立たせるスタイルである。ちょうど、K&Rスタイルでブロックの終わりの中括弧の字下げレベルを戻さないスタイルである。
// Cの例 for (i = 0; i < 10; i++) { if (i % 2 == 0) { doSomething(i);
else { doSomethingElse(i);
マークアップ言語では次のようになる。
| lots of stuff... more stuff || alternative for short lines || etc.
... etc
Lispスタイル さらに、終わりの中括弧を別の行にしない書き方もある。このスタイルでは中括弧はブロックの識別の役に立たないが、情報のない行を省くという利点もある。Lispで非常に一般的であるためLispスタイルと呼ぶことができるほか、Pythonスタイルとも呼べる。Pythonには括弧はないが、以下のコードブロックが示すように、レイアウトは非常に似ている。Pythonではレイアウトは言語の一部であり、オフサイドルールと呼ばれる。
for(i = 0; i < 10; i++) { if(i % 2 == 0) { doSomething(i); } else { doSomethingElse(i); } }
// Cの例 for (i = 0; i < 10; i++) {if (i % 2 == 0) {doSomething(i);} else {doSomethingElse(i); doThirdThing(i);}}
# Pythonの例 for i in range(10): if i % 2 == 0: do_something(i) else: do_something_else(i) do_third_thing(i)
;; Lispの例 (dotimes (i 10)