STYLE(9)

名称
style - カーネルソースファイルのスタイルガイド

解説
このファイルは FreeBSD ソースツリーのカーネルソースに好ましいスタイルを明記しています。 これはユーザランドのコードスタイルの手引きでもあります。 例において、スタイル規則の多くを暗黙的に使用しています。 style がこれらの事例について言及していないと決め付ける前に、 注意して例を確認してください。 style はそのような事柄については記述していません。

    /*
     * FreeBSD のためのスタイルガイドです。
     * CSRG の KNF (Kernel Normal Form, カーネル標準書式) に基づいています。
     *
     *	@(#)style	1.14 (Berkeley) 4/28/95
     * $FreeBSD: src/share/man/man9/style.9,v 1.32.2.19 2002/04/14 19:28:03 asmodai Exp $
     */
    /*
     * とても重要な 1 行のコメントはこのようにします。
     */
    /* 殆どの 1 行のコメントはこのようにします。 */
    /*
     * 複数行にわたるコメントはこのようにします。実際の文章を書きます。実際の
     * 段落に見えるように埋めていきます。
     */

著作権ヘッダの後には空行を 1 行入れ、ソースファイルには rcsid を付けます。 バージョン管理システムの ID タグは、ファイル中に 1 個のみあるべきです (このファイルでは違いますが)。 C/C++ ソースファイル以外はこの例に従いますが、 C/C++ ソースファイルは以降の例に従います。 外部から入手したファイルの すべての VCS (バージョン管理システム) リビジョン識別子は、 存在すれば維持します。 これには、ファイルの来歴を示す複数の ID も含みます。 一般的に、 ‘$’ も含めて、ID はそのままとします。 外部からの VCS ID の前に "From" を付ける理由はありません。 ほとんどの非 FreeBSD の VCS ID は、 コメント中ではタブでインデントされているでしょう。

    #include <sys/cdefs.h>
    __RCSID("@(#)style	1.14 (Berkeley) 4/28/95");
    __FBSDID("$FreeBSD: src/share/man/man9/style.9,v 1.32.2.19 2002/04/14 19:28:03 asmodai Exp $");

ヘッダファイルの前に、空行を 1 行付けます。

カーネルのインクルードファイル (すなわち、 sys/*.h ) が初めに来ます。 通常、 <sys/types.h> または <sys/param.h> のどちらかが必要ですが、 両方は必要ないでしょう。 <sys/types.h> は <sys/cdefs.h> をインクルードしており、 依存関係は問題ありません。

    #include <sys/types.h>		/* 山括弧による非ローカルインクルード */

ネットワークプログラムである場合は、 次にネットワークインクルードファイルを置きます。

    #include <net/if.h>
    #include <net/if_dl.h>
    #include <net/route.h>
    #include <netinet/in.h>
    #include <protocols/rwhod.h>

カーネル用のファイルには、 /usr/include 中のファイルを使用しないでください。

それから空行を置き、 /usr インクルードファイルを続けます。 /usr インクルードファイルはアルファベット順にソートされているべきです。

    #include <stdio.h>

グローバルなパス名は /usr/include/paths.h で定義されています。 プログラムにローカルなパス名はローカルディレクトリの "pathnames.h" に入れます。

    #include <paths.h>

それから、空行があって、ユーザインクルードファイルが来ます。

    #include "pathnames.h"		/* " " によるローカルインクルード */

アプリケーションインタフェースを実装している場合を除き、 実装の名前空間で #define したり名前を定義したりしてはいけません。

“安全でない” マクロ (副作用を持っているもの) の名前と、 明らかな定数のマクロの名前はすべて大文字です。 式のように展開されるマクロは、単一のトークンにするか外側に括弧をつけます。 #define とマクロ名の間にタブ文字を 1 個入れます。 マクロがある関数のインライン展開である場合は、 関数名は全て小文字で、マクロはすべて大文字の同じ名前を持ちます。 マクロが 1 行以上必要な場合は、ブレース ‘({’ と ‘}’) を使用します。 バックスラッシュは右揃えします。こうすると読みやすくなります。 マクロが複合文をカプセル化する場合には、それを do ループで囲みます。 これにより、 if 文で安全に使用できます。 最後の文の終端のセミコロンは、 マクロではなくマクロの実施時に付けられるべきです。 これにより、清書器やエディタで文法解析しやすくなります。

    #define	MACRO(x, y) do {						\
    	variable = (x) + (y);						\
    	(y) += 2;							\
    } while(0)

列挙値は全て大文字を使用します。

    enum enumtype { ONE, TWO } et;

構造体の中で変数を宣言する時には、 使用順、サイズ順、アルファベット順にソートして宣言します。 最初の区分は通常適用しませんが、例外があります。 各宣言は、それぞれ独立した行にて行います。 構造体の名前の位置を、あなたの判断で読み易いように、 タブ 1 個または 2 個を使用して揃えてください。 ほとんどのメンバを揃えるのに十分であれば、単一のタブを使用すべきです。 非常に長い型の後の名前は、単一の空白で区切られるべきです。

重要な構造体は、それが使用されるファイルの先頭で宣言されるか、 複数のソースファイルで使用される場合は別のヘッダファイルで宣言されるべきです。 構造体がヘッダファイルで宣言されている場合には、 それら構造体の使用は、宣言とは分けられるべきで、かつ extern であるべきです。

    struct foo {
    	struct foo	*next;		/* 使用中の foo のリスト */
    	struct mumble	amumble;	/* mumble のコメント */
    	int		bar;		/* コメントを揃えようとしています */
    	struct verylongtypename *baz;	/* タブ 2 個には収まりません */
    };
    struct foo *foohead;			/* グローバルな foo リストの先頭 */

可能な時には必ず、あなた自身でリストを操作するのではなく、 queue(3) マクロを使用してください。 従って、前の例をより良く書くと次のようになります。

    #include <sys/queue.h>
    struct foo {
    	LIST_ENTRY(foo)	link;		/* foo リストにキューマクロを使用 */
    	struct mumble	amumble;	/* mumble のコメント */
    	int		bar;		/* コメントを揃えようとしています */
    	struct verylongtypename *baz;	/* タブ 2 個には収まりません */
    };
    LIST_HEAD(, foo) foohead;		/* グローバルな foo リストの先頭 */

構造体の型に typedef を使用する事は避けてください。 使用してしまうと、 構造体へのポインタを不透明 (opaque) に使用することが、 アプリケーションにとって不可能となります。 通常の struct タグを使用すると、これが可能となり、かつ有益です。 規約が typedef を要求する場合には、その名前を構造体タグに一致させます。 標準 C または によって明示されたものを除いては、 “_t” で終る typedef を避けてください。

    /* 構造体名と typedef を一致させます */
    typedef struct bar {
    	int	level;
    } BAR;
    typedef	int		foo;		/* これは foo です */
    typedef	const long	baz;		/* これは baz です */

全ての関数はどこかでプロトタイプされます。

私的な関数 (すなわち、他のどこでも使用されない関数など) の関数プロトタイプは、 最初のソースモジュールの先頭に置かれます。 単一のソースモジュールにローカルな関数は、 static で宣言されるべきです。

カーネルの別の部分から使用される関数は、 関連のあるインクルードファイルの中でプロトタイプされます。

複数のモジュールでローカルに使用される関数は、 "extern.h" 等の分離したヘッダファイルの中に置かれます。

一般にソースファイルが K&R 旧約聖書コンパイラで コンパイル可能である (べき) 時にのみ、 インクルードファイル <sys/cdefs.h> の __P マクロを使用します。 新しいコードでの __P マクロの使用は反対されていますが、 既存のファイルに対する修正はそのファイルの規約と首尾一貫しているべきです。

ファイルの 50% かそれ以上を巻き込んだ修正の場合は、 一般にコードは “新しいコード” とみなすことができます。 これは既存のコードの慣例を破り、 現在の style ガイドラインを使用するのに十分です。

カーネルはパラメータの型に関連付けられた名前を持ちます。 例えば、カーネル内でこのように使用します。

    void	function(int fd);

ユーザランドのアプリケーションに対して見えるヘッダファイルの中では、 可視のプロトタイプは、 型を伴った “保護された” (アンダスコアで開始する) 名前を使用するか、 型だけで名前を使用しないかのどちらかが必要です。 保護された名前の使用がより望ましいです。 例えば、このように使用します。

    void	function(int);

または

    void	function(int _fd);

プロトタイプは関数名の行揃えを行なうために、タブの後に追加のスペース文字を 置いても構いません。

    static char	*function(int _arg, const char *_arg2, struct foo *_arg3,
    		    struct bar *_arg4);
    static void	 usage(void);
    /*
     * 全ての主要なルーチンはそれが何をするのかを簡潔に記述した
     * コメントを持つべきです。"main" ルーチンの前のコメントは
     * そのプログラムが何をするのかを記述するべきです。
     */
    int
    main(int argc, char *argv[])
    {
    	long num;
    	int ch;
    	char *ep;

一貫性のために、オプションの解析には getopt(3) が使用されるべきです。 getopt(3) 呼び出しと switch 文では、オプションをソートすべきですが、 switch 文のカスケードの一部の場合は例外です。 switch 文のカスケード要素は FALLTHROUGH コメントを持つべきです。 数値の引数は精度をチェックされるべきです。 到達できないコードは NOTREACHED コメントを持つべきです。

    	while ((ch = getopt(argc, argv, "abn:")) != -1)
    		switch (ch) {		/* switch をインデント */
    		case 'a':		/* case はインデントしない */
    			aflag = 1;
    			/* FALLTHROUGH */
    		case 'b':
    			bflag = 1;
    			break;
    		case 'n':
    			num = strtol(optarg, &ep, 10);
    			if (num <= 0 || *ep != '\0') {
    				warnx("illegal number, -n argument -- %s",
    				    optarg);
    				usage();
    			}
    			break;
    		case '?':
    		default:
    			usage();
    			/* NOTREACHED */
    		}
    	argc -= optind;
    	argv += optind;

予約語 (if, while, for, return, switch) の後にスペースを入れます。 何も伴わないかただ 1 つの文を伴う制御文は、ブレースを使用しません。 1 つの文が 複数行である文の場合には、これは許されます。 無限ループは while ではなく for で行ないます。

    	for (p = buf; *p != '\0'; ++p)
    		;	/* 何もなし */
    	for (;;)
    		stmt;
    	for (;;) {
    		z = a + really + long + statement + that + needs +
    		    two lines + gets + indented + four + spaces +
    		    on + the + second + and + subsequent + lines;
    	}
    	for (;;) {
    		if (cond)
    			stmt;
    	}
    	if (val != NULL)
    		val = realloc(val, newsize);

for ループの各部は空のまま残しても構いません。 異常に複雑なルーチンでない限りは、ブロックの中に宣言を置いてはなりません。

    	for (; cnt < 15; cnt++) {
    		stmt1;
    		stmt2;
    	}

インデントは 8 文字のタブです。 第 2 レベルのインデントは 4 文字のスペースです。 長い分を折り返す必要がある場合、オペレータを行末に置きます。

    	while (cnt < 20 && this_variable_name_is_too_long_for_its_own_good &&
    	    ep != NULL)
    		z = a + really + long + statement + that + needs +
    		    two lines + gets + indented + four + spaces +
    		    on + the + second + and + subsequent + lines;

空白文字を行末に追加してはいけません。 また、インデントを形成するためには、タブとその後にスペースのみを使用します。 タブが生み出す以上のスペースや、タブの前のスペースは使用しません。

ブレースの終了と開始は else と同じ行に置かれます。 必要でないブレースは省いても構いません。

    	if (test)
    		stmt;
    	else if (bar) {
    		stmt;
    		stmt;
    	} else
    		stmt;

関数名の後はスペースを空けません。 コンマの後にはスペースを持ちます。 ‘(’ または ‘[’ の後ろまたは ‘’] または ‘’) の前にはスペースを空けません。

    	error = function(a1, a2);
    	if (error != 0)
    		exit(error);

単項演算子はスペースを要求しませんが、二項演算子は要求します。 優先順位が要求する場合または文が括弧なしでは混乱する場合以外は、 括弧は使用しません。 他人はあなたよりも混乱しやすいかもしれないということを覚えておいてください。 あなたは以下を理解できますか?

    	a = b->c[0] + ~d == (e || f) || g && h ? i : j >> 1;
    	k = !(l & FLAGS);

成功時には 0 で、または sysexits(3) にあらかじめ定義してある値で exit するべきです。

    	exit(EX_OK);	/*
    			 * "Exit 0 on success." (成功時は 0 で終了)
    			 * の様に明白なコメントは避けてください
    			 */
    }

関数の型は、関数自身に先行する行にあるべきです。

    static char *
    function(int a1, int a2, float fl, int a4)
    {

関数の中で変数を宣言する時には、サイズ順に、次にアルファベット順に ソートして宣言します。 1 行に複数の宣言は可能です。 行が溢れる場合は、型の予約語を再度使用します。

宣言時に変数を初期化することによってコードを 不明瞭にしない様に注意してください。 この機能は良く考えて使用してください。 初期化に関数呼び出しを使用しないでください。

    	struct foo one, *two;
    	double three;
    	int *four, five;
    	char *six, seven, eight, nine, ten, eleven, twelve;
    	four = myfunction();

他の関数の内部で関数を宣言しないでください。 ANSI C によると、このような宣言は、宣言のネスティングによらず、 ファイルスコープになります。 ローカルスコープに見えるものの中にファイルの宣言を隠すことは好ましくなく、 良いコンパイラは苦情を言います。

キャストと sizeof 演算子の後にはスペースを続けません。 この規則は indent(1) が理解しないことに注意してください。

NULL は、好まれるヌルポインタ定数です。 コンパイラが型を知っている文脈、例えば代入では、 (type *)0 または (type *)NULL の代わりに、 NULL を使用します。 他の文脈では、特に全ての関数の引数では、 (type *)NULL を使用します。 (関数のプロトタイプがスコープ外かもしれない場合に、 キャストはいろいろな引数にとって必須で、その他の引数にとっても必要です。) ポインタは NULL と比較します。例えば、

    !(p = f())

ではなく、このように使います。

    (p = f()) == NULL

真理値ではない場合、テストには! を使用しないでください。 例えば、下記のように使います。

    if (*p == '\0')

下記のようには使いません。

    if (!*p)

void * を返すルーチンでは、 戻り値をどのポインタ型にもキャストしてはなりません。

err(3) または warn(3) を使用し、勝手に作らないでください。

    	if ((four = malloc(sizeof(struct foo))) == NULL)
    		err(1, (char *)NULL);
    	if ((six = (int *)overflow()) == NULL)
    		errx(1, "number overflowed");
    	return (eight);
    }

古いスタイルの関数宣言はこのようになっています。

    static char *
    function(a1, a2, fl, a4)
    	int a1, a2;	/* int 型も宣言します、デフォルトにしないこと */
    	float fl;	/* double と float の違いに気を付けてください */
    	int a4;		/* 出てきた順に宣言します */
    {

あなたが明確に K&R との互換性を必要とする場合以外は、 ANSI の関数宣言を使用してください。 長いパラメータリストの折り返しには、 4 個の空白による通常のインデントを付けます。

可変個数の引数はこのようにします。

    #include <stdarg.h>
    void
    vaf(const char *fmt, ...)
    {
    	va_list ap;
    	va_start(ap, fmt);
    	STUFF;
    	va_end(ap);
    	/* void 型の関数に return は不要です */
    }
    static void
    usage()
    {
    	/* 関数がローカル変数を持たない場合、空行をいれます */

fputs(3), puts(3), putchar(3) 等ではなく、 printf(3) を使用してください。 これは速くて大抵はきれいで、言うまでもなくつまらないバグを避けます。

使用法 (usage) の文はマニュアルページの SYNOPSIS (書式) の様であるべきです。 使用法の文は、次の構造であるべきです:

1.  オペランドの無いオプションが、最初にアルファベット順に、 1 組の大括弧 ‘([’ と ‘’]) でくくられます。

2.  オプションとそのオペランドがこれもアルファベット順に続き、 それぞれのオプションとその引数を 1 組の大括弧でくくります。

3.  必須の引数 (もしあれば) が続き、 コマンドラインで指定されるべき順で一覧されます。

4.  最後に、 すべての任意の引数が指定されるべき順で、 すべて大括弧の中に一覧されます。

縦棒 (‘|’) は、 “二者択一” のオプションまたは引数を分割し、 同時に使用するオプションと引数は、単一の大括弧でくくります。

    "usage: f [-aDde] [-b b_arg] [-m m_arg] req1 req2 [opt1 [opt2]]\n"
    "usage: f [-a | -b] [-c [-dEe] [-n number]]\n"

    	(void)fprintf(stderr, "usage: f [-ab]\n");
    	exit(EX_USAGE);
    }

マニュアルページのオプション記述は、 純粋なアルファベット順であるべきであることに注意してください。 つまり、オプションが引数を取るか否かに関わらないということです。 アルファベット順は、前述の大文字小文字の順序を考慮に入れるべきです。

新しい中心的なカーネルのコードは、適度に style ガイドに従うべきです。 サードパーティが保守するモジュールやデバイスドライバのためのガイドラインは より緩やかですが、最低限内部的には彼らの一貫したスタイルであるべきです。

ソースリポジトリの文体の変更 (空白文字の変更を含む) は困難で、 正当な理由なしには避けるべきです。 リポジトリの中のおおよそ KNF style に適合しているコードは、この適合から離れてはなりません。

可能な時にはいつでも、 コードはコードチェッカ (例えば、 lint(1) または gcc -Wall ) を 通過し、発生する警告は最小限となるべきです。

関連項目
indent(1), lint(1), err(3), sysexits(3), warn(3)

歴史
このページは 4.4BSD Lite2 リリースの src/admin/style/style ファイルに大きく基づいていて、 現在の実装と FreeBSD プロジェクトの要望を反映して、頻繁に更新しています。