STYLE(9) FreeBSD カーネル開発者マニュアル 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.110.2.1
2005/03/01 12:44:49 brueffer Exp $ /* /* 殆どの 1 行のコメントはこのようにします。 */ /* 著作権のヘッダは複数行にわたるコメントであるべきで、コメントの最初の行は 次のように星 (アスタリスク) の後ろにダッシュ (-) を付けます: /*- * Copyright (c) 1984-2025 John Q. Public. All Rights Reserved. * * 長くて、退屈なライセンスはここに記述しますが、簡潔にするために * 編集しています */ 自動スクリプトは最初のカラムが ‘‘/*-’’ で始まるすべてのコメントを対照とし てツリーからライセンス情報を集めます。利用者がライセンスまたは著作権表示 でもない最初のカラムで始まるコメントを最初のカラムから始まるコメントでラ イセンスや著作権表示でないものを indent(1) に再整形させたくない場合は、そ れらのコメントのダッシュを星に変えてください。最初のコメント以外のカラム で始まるコメントは決してライセンス声明とはみなしません。訳注: 行頭にない ものはライセンス表明とみなしません。 著作権ヘッダの後には空行を 1 行入れ、ソースファイルには rcsid を付けま す。バージョン管理システムの ID タグは、ファイル中に 1 個のみあるべきです (このファイルでは違いますが)。 C/C++ ソースファイル以外はこの例に従います が、 C/C++ ソースファイルは以降の例に従います。外部から入手したファイルの すべての VCS (バージョン管理システム) リビジョン識別子は、存在すれば維持 します。これには、ファイルの来歴を示す複数の ID も含みます。一般的に、外 来の ID またはその下部構造は編集しません。さもなければ (‘‘#if defined(LIBC_SCCS)’’ のように) 囲まれていない場合には、全ての互換性のない 小片を隠すため、およびその ID をオブジェクトファイルから追い出しておくた めに、両方を ‘‘#if 0 ... #endif’’ の中に囲みます。ファイルの名前が変更さ れた場合には、外来の VCS ID の前に ‘‘From: ’’ のみを追加します。 #if 0 #ifndef lint static char sccsid[] = "@(#)style 1.14 (Berkeley) 4/28/95"; #endif /* not lint */ #endif #include <sys/cdefs.h> __FBSDID("$FreeBSD: src/share/man/man9/style.9,v 1.110.2.1 2005/03/01 12:44:49 brueffer 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/include のファイルを続けます。 /usr/include の ファイルはアルファベット順にソートされているべきです。 #include <stdio.h> グローバルなパス名は <paths.h> で定義されています。プログラムにローカルな パス名はローカルディレクトリの "pathnames.h" に入れます。 #include <paths.h> それから、空行があって、ユーザインクルードファイルが来ます。 #include "pathnames.h" /* " " によるローカルインクルード */ アプリケーションインタフェースを実装している場合を除き、実装の名前空間で #define したり名前を定義したりしてはいけません。 ‘‘安全でない’’ マクロ (副作用を持っているもの) の名前と、明らかな定数のマ クロの名前はすべて大文字です。式のように展開されるマクロは、単一のトーク ンにするか外側に括弧をつけます。 #define とマクロ名の間にタブ文字を 1 個 入れます。マクロがある関数のインライン展開である場合は、関数名は全て小文 字で、マクロはすべて大文字の同じ名前を持ちます。バックスラッシュは右揃え します。こうすると読みやすくなります。マクロが複合文をカプセル化する場合 には、それを do ループで囲みます。これにより、 if 文で安全に使用できま す。最後の文の終端のセミコロンは、マクロではなくマクロの実施時に付けられ るべきです。これにより、清書器やエディタで文法解析しやすくなります。 #define MACRO(x, y) do { \ |
variable = (x) + (y); |
\ |
||||||||
(y) += 2; |
\ |
} while (0) コードが #ifdef または #if を使用して条件付きでコンパイルされるときには、 どこで条件付きでコンパイルされるコードが終了するのかを読む人が容易に識別 することが可能にするために、それに続く適合する #endif または #else にコメ ントを追加しても構いません。このコメントは (主観的に) 長い部分、20 行以上 の部分、またはネストされた #ifdef の連続が読む人を混乱させるかもしれない とき、にのみ使用されるべきです。たとえコンパイルされない領域が小さくなる かもしれないでも、 lint(1) の目的のために条件付きでコンパイルされない個所 のために、例外が作られても構いません。そのコメントは #endif または #else から 1 つの空白によって分離されるべきです。短い条件付きでコンパイルされる 部分のために、終わりのコメントを使用するべきではありません。 #endif のためのコメントは対応する #if または #ifdef で使用されている表現 に合わせるべきです。 #else および #elif のためのコメントは先行する #if お よび/または #elif 文に使用されている表現の反対に合わせるべきです。コメン トの中では、補助表現 ‘‘defined(FOO)’’ は ‘‘FOO’’ と省略されます。コメント の目的のためには、 ‘‘#ifndef FOO’’ は ‘‘#if !defined(FOO)’’ とみなされま す。 #ifdef KTRACE #include <sys/ktrace.h> #endif #ifdef COMPAT_43 /* 大きな部分が、または他の条件付きのコードがここに */ #else /* !COMPAT_43 */ /* またはここに */ #endif /* COMPAT_43 */ #ifndef COMPAT_43 /* 更に別の大きな部分が、または他の条件付きのコードがここに */ #else /* COMPAT_43 */ /* またはここに */ #endif /* !COMPAT_43 */ このプロジェクトは、 u_intXX_t 形式の古い BSD スタイルの整数識別子よりも むしろ、 uintXX_t 形式の ISO/IEC 9899:1999 (‘‘ISO C99’’) の符号なし整数識 別子を使用するように、徐々に移行しています。新しいコードは後者を使用する べきで、さらにその領域の他の主要な作業が完了し、古い BSD スタイルを好むた めの優先する理由がない場合には、古いコードは新しい形式に変換されるべきで す。空白文字のコミットと同様に、 uintXX_t のみのコミットをするよう、考慮 すべきです。 列挙値は全て大文字を使用します。 enum enumtype { ONE, TWO } et; 宣言の中では、型に関係付けられたトークンを除いて、アスタリスクと隣接した トークンの間には空白文字を置きません。 (これらの識別子は基本の型の名前、 型の修飾語句、および今宣言されようとしているもの以外の typedef 名です。) これらの識別子はアスタリスクから 1 つの空白で分離します。 構造体の中で変数を宣言する時には、使用順、サイズ順 (大きいものから小さな ものへ)、アルファベット順にソートして宣言します。最初の区分は通常適用しま せんが、例外があります。各宣言は、それぞれ独立した行にて行います。構造体 の名前の位置を、あなたの判断で読み易いように、タブ 1 個または 2 個を使用 して揃えてください。少なくとも 90% のメンバの名前を揃えるのに十分な場合に は、 1 つだけのタブを使用するべきです。非常に長い型の後の名前は、単一の空 白で区切られるべきです。 重要な構造体は、それが使用されるファイルの先頭で宣言されるか、複数のソー スファイルで使用される場合は別のヘッダファイルで宣言されるべきです。構造 体がヘッダファイルで宣言されている場合には、それら構造体の使用は、宣言と は分けられるべきで、かつ 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 を使用する事は避けてください。 typedef は、その下位 にある型を適切に隠さないので、問題となり得ます。例えば、typedef が構造体 そのものであるのか、構造体へのポインタであるのか、あなたが知る必要があり ます。更に、typedef は正確に 1 度だけ宣言しなければなりませんが、不完全な 構造体型は必要な回数だけ宣言可能です。 typedef はスタンドアロンなヘッダ ファイル中で使用することが困難です。 typedef を定義するヘッダは、この typedef を使用するヘッダの前にインクルードするか、この typedef を使用する ヘッダによってインクルードする必要があります (これは名前空間の汚染となり ます)。さもなければ、typedef を得るための裏口が必要となってしまいます。 規約が typedef を要求する場合には、その名前を構造体タグに一致させます。標 準 C または POSIX によって明示されたものを除いては、 ‘‘_t’’ で終る typedef を避けてください。 /* 構造体名と typedef を一致させます */ |
typedef |
struct bar { |
|||
int |
level; |
} BAR; |
typedef |
int |
foo; |
/* これは foo です */ |
||||
typedef |
const long |
baz; |
/* これは baz です */ |
全ての関数はどこかでプロトタイプされます。 私的な関数 (すなわち、他のどこでも使用されない関数など) の関数プロトタイ プは、最初のソースモジュールの先頭に置かれます。単一のソースモジュールに ローカルな関数は、 static で宣言されるべきです。 カーネルの別の部分から使用される関数は、関連のあるインクルードファイルの 中でプロトタイプされます。関数プロトタイプは、異なる順序の使用を強制する 理由がない場合には、なるべくアルファベット順の論理的な順序で整列されるべ きです。 複数のモジュールでローカルに使用される関数は、 "extern.h" 等の分離した ヘッダファイルの中に置かれます。 __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); |
/* |
char *ep; |
|
long num; |
|
int ch; |
一貫性のために、オプションの解析には getopt(3) が使用されるべきです。 getopt(3) 呼び出しと switch 文では、オプションをソートすべきですが、 switch 文のカスケードの一部の場合は例外です。 switch 文のカスケード要素は FALLTHROUGH コメントを持つべきです。数値の引数は精度をチェックされるべき です。到達できないコードは NOTREACHED コメントを持つべきです。 while ((ch = getopt(argc, argv, "abNn:")) != -1) |
switch (ch) { |
/* switch をインデント */ |
|||||
case ’a’: |
/* case はインデントしない */ |
|||||
aflag = 1; |
||||||
/* FALLTHROUGH */ |
||||||
case ’b’: |
||||||
bflag = 1; |
||||||
break; |
||||||
case ’N’: |
||||||
Nflag = 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 && |
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 で終了) |
||||
* の様に分かりきったコメントは避けてください |
||||
*/ |
} 関数の型は、関数自身に先行する行にあるべきです。関数の本体の開始のブレー スは、単独で 1 行であるべきです。 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) が理解しないことに注意してください。 sizeof は常に括弧をつけて 書かれます。冗長な括弧の規則は sizeof(var) の事例には適用されません。 NULL は、好まれるヌルポインタ定数です。コンパイラが型を知っている文脈、例 えば代入では、 (type *)0 または (type *)NULL の代わりに、 NULL を使用しま す。他の文脈では、特に全ての関数の引数では、 (type *)NULL を使用します。 (関数のプロトタイプがスコープ外かもしれない場合に、キャストはいろいろな引 数にとって必須で、その他の引数にとっても必要です。) ポインタは NULL と比 較します。例えば、次のように使います: (p = f()) == NULL 次のようには使いません: !(p = f()) 真理値 (ブール値) ではない場合、テストには ! を使用しないでください。例え ば、次のように使います: if (*p == ’\0’) 次のようには使いません: if (!*p) void * を返すルーチンでは、戻り値をどのポインタ型にもキャストしてはなりま せん。 return 文の値は括弧で囲まれているべきです。 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 |
/* 関数がローカル変数を持たない場合、空行をいれます */ |
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" (void)fprintf(stderr, "usage: f [-ab]\n"); |
exit(EX_USAGE); |
} マニュアルページのオプション記述は、純粋なアルファベット順であるべきであ ることに注意してください。つまり、オプションが引数を取るか否かに関わらな いということです。アルファベット順は、前述の大文字小文字の順序を考慮に入 れるべきです。 新しい中心的なカーネルのコードは、適度に style ガイドに従うべきです。サー ドパーティが保守するモジュールやデバイスドライバのためのガイドラインはよ り緩やかですが、最低限内部的には彼らの一貫したスタイルであるべきです。 ソースリポジトリの文体の変更 (空白文字の変更を含む) は困難で、正当な理由 なしには避けるべきです。リポジトリの中のおおよそ FreeBSD KNF style に適合 しているコードは、この適合から離れてはなりません。 可能な時にはいつでも、コードはコードチェッカ (例えば、 lint(1) または gcc −Wall) を通過し、発生する警告は最小限となるべきです。 |
関連項目
indent(1), lint(1), err(3), sysexits(3), warn(3), style.Makefile(5) |
歴史
このページは 4.4BSD−Lite2 リリースの src/admin/style/style ファイルに大き く基づいていて、現在の実装と FreeBSD プロジェクトの要望を反映して、頻繁に 更新しています。 FreeBSD 10.0 December 7, 2001 FreeBSD 10.0 |