doc/ja_JP.eucJP/man/man9/style.9
2002-04-29 01:09:03 +00:00

704 lines
18 KiB
Groff

.\" Copyright (c) 1995-2001 FreeBSD Inc.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL [your name] OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" %FreeBSD: src/share/man/man9/style.9,v 1.32.2.19 2002/04/14 19:28:03 asmodai Exp %
.\" $FreeBSD$
.\"
.Dd December 7, 2001
.Dt STYLE 9
.Os
.Sh 名称
.Nm style
.Nd カーネルソースファイルのスタイルガイド
.Sh 解説
このファイルは
.Fx
ソースツリーのカーネルソースに好ましいスタイルを明記しています。
これはユーザランドのコードスタイルの手引きでもあります。
例において、スタイル規則の多くを暗黙的に使用しています。
.Nm
がこれらの事例について言及していないと決め付ける前に、
注意して例を確認してください。
.Nm
はそのような事柄については記述していません。
.\" $ と FreeBSD を続けるとキーワード置換されるので、\& を挿入
.\" 2001/05/23 horikawa@jp.FreeBSD.org
.Bd -literal
/*
* 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 行のコメントはこのようにします。 */
/*
* 複数行にわたるコメントはこのようにします。実際の文章を書きます。実際の
* 段落に見えるように埋めていきます。
*/
.Ed
.Pp
著作権ヘッダの後には空行を 1 行入れ、ソースファイルには
.Va rcsid
を付けます。
バージョン管理システムの ID タグは、ファイル中に 1 個のみあるべきです
(このファイルでは違いますが)。
C/C++ ソースファイル以外はこの例に従いますが、
C/C++ ソースファイルは以降の例に従います。
外部から入手したファイルの
すべての VCS (バージョン管理システム) リビジョン識別子は、
存在すれば維持します。
これには、ファイルの来歴を示す複数の ID も含みます。
一般的に、
.So Li $ Sc
も含めて、ID はそのままとします。
外部からの VCS ID の前に
.Qq Li "From"
を付ける理由はありません。
ほとんどの非
.Fx
の VCS ID は、
コメント中ではタブでインデントされているでしょう。
.Bd -literal
#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 $");
.Ed
.Pp
ヘッダファイルの前に、空行を 1 行付けます。
.Pp
カーネルのインクルードファイル (すなわち、
.Pa sys/*.h
) が初めに来ます。
通常、
.Aq Pa sys/types.h
または
.Aq Pa sys/param.h
のどちらかが必要ですが、
両方は必要ないでしょう。
.Aq Pa sys/types.h
.Aq Pa sys/cdefs.h
をインクルードしており、
依存関係は問題ありません。
.Bd -literal
#include <sys/types.h> /* 山括弧による非ローカルインクルード */
.Ed
.Pp
ネットワークプログラムである場合は、
次にネットワークインクルードファイルを置きます。
.Bd -literal
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <netinet/in.h>
#include <protocols/rwhod.h>
.Ed
.Pp
カーネル用のファイルには、
.Pa /usr/include
中のファイルを使用しないでください。
.Pp
それから空行を置き、
.Pa /usr
インクルードファイルを続けます。
.Pa /usr
インクルードファイルはアルファベット順にソートされているべきです。
.Bd -literal
#include <stdio.h>
.Ed
.Pp
グローバルなパス名は
.Pa /usr/include/paths.h
で定義されています。
プログラムにローカルなパス名はローカルディレクトリの
.Qq Pa pathnames.h
に入れます。
.Bd -literal
#include <paths.h>
.Ed
.Pp
それから、空行があって、ユーザインクルードファイルが来ます。
.Bd -literal
#include "pathnames.h" /* " " によるローカルインクルード */
.Ed
.Pp
アプリケーションインタフェースを実装している場合を除き、
実装の名前空間で
.Ic #define
したり名前を定義したりしてはいけません。
.Pp
.Dq Li 安全でない
マクロ (副作用を持っているもの) の名前と、
明らかな定数のマクロの名前はすべて大文字です。
式のように展開されるマクロは、単一のトークンにするか外側に括弧をつけます。
.Ic #define
とマクロ名の間にタブ文字を 1 個入れます。
マクロがある関数のインライン展開である場合は、
関数名は全て小文字で、マクロはすべて大文字の同じ名前を持ちます。
.\" XXX 上記は名前が同じマクロを #undef すれば関数を使える
.\" という ANSI のスタイルと衝突します。
.\" これは MALLOC() については言えないし、インライン関数を使う時の
.\" 一般的なやりかたではありません。
マクロが 1 行以上必要な場合は、ブレース
.Ql ( \&{
.Ql \&} )
を使用します。
バックスラッシュは右揃えします。こうすると読みやすくなります。
マクロが複合文をカプセル化する場合には、それを
.Ic do
ループで囲みます。
これにより、
.Ic if
文で安全に使用できます。
最後の文の終端のセミコロンは、
マクロではなくマクロの実施時に付けられるべきです。
これにより、清書器やエディタで文法解析しやすくなります。
.Bd -literal
#define MACRO(x, y) do { \e
variable = (x) + (y); \e
(y) += 2; \e
} while(0)
.Ed
.Pp
列挙値は全て大文字を使用します。
.Bd -literal
enum enumtype { ONE, TWO } et;
.Ed
.Pp
構造体の中で変数を宣言する時には、
使用順、サイズ順、アルファベット順にソートして宣言します。
最初の区分は通常適用しませんが、例外があります。
各宣言は、それぞれ独立した行にて行います。
構造体の名前の位置を、あなたの判断で読み易いように、
タブ 1 個または 2 個を使用して揃えてください。
ほとんどのメンバを揃えるのに十分であれば、単一のタブを使用すべきです。
非常に長い型の後の名前は、単一の空白で区切られるべきです。
.Pp
重要な構造体は、それが使用されるファイルの先頭で宣言されるか、
複数のソースファイルで使用される場合は別のヘッダファイルで宣言されるべきです。
構造体がヘッダファイルで宣言されている場合には、
それら構造体の使用は、宣言とは分けられるべきで、かつ
.Ic "extern
であるべきです。
.Bd -literal
struct foo {
struct foo *next; /* 使用中の foo のリスト */
struct mumble amumble; /* mumble のコメント */
int bar; /* コメントを揃えようとしています */
struct verylongtypename *baz; /* タブ 2 個には収まりません */
};
struct foo *foohead; /* グローバルな foo リストの先頭 */
.Ed
.Pp
可能な時には必ず、あなた自身でリストを操作するのではなく、
.Xr queue 3
マクロを使用してください。
従って、前の例をより良く書くと次のようになります。
.Bd -literal
#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 リストの先頭 */
.Ed
.Pp
構造体の型に typedef を使用する事は避けてください。
使用してしまうと、
構造体へのポインタを不透明 (opaque) に使用することが、
アプリケーションにとって不可能となります。
通常の struct タグを使用すると、これが可能となり、かつ有益です。
規約が
.Ic typedef
を要求する場合には、その名前を構造体タグに一致させます。
標準 C または \*[Px]
によって明示されたものを除いては、
.Dq Li _t
で終る typedef を避けてください。
.Bd -literal
/* 構造体名と typedef を一致させます */
typedef struct bar {
int level;
} BAR;
typedef int foo; /* これは foo です */
typedef const long baz; /* これは baz です */
.Ed
.Pp
全ての関数はどこかでプロトタイプされます。
.Pp
私的な関数 (すなわち、他のどこでも使用されない関数など) の関数プロトタイプは、
最初のソースモジュールの先頭に置かれます。
単一のソースモジュールにローカルな関数は、
.Ic static
で宣言されるべきです。
.Pp
カーネルの別の部分から使用される関数は、
関連のあるインクルードファイルの中でプロトタイプされます。
.Pp
複数のモジュールでローカルに使用される関数は、
.Qq Pa extern.h
等の分離したヘッダファイルの中に置かれます。
.Pp
一般にソースファイルが K&R 旧約聖書コンパイラで
コンパイル可能である (べき) 時にのみ、
インクルードファイル
.Aq Pa sys/cdefs.h
.Dv __P
マクロを使用します。
新しいコードでの
.Dv __P
マクロの使用は反対されていますが、
既存のファイルに対する修正はそのファイルの規約と首尾一貫しているべきです。
.Pp
ファイルの 50% かそれ以上を巻き込んだ修正の場合は、
一般にコードは
.Dq 新しいコード
とみなすことができます。
これは既存のコードの慣例を破り、
現在の
.Nm
ガイドラインを使用するのに十分です。
.Pp
カーネルはパラメータの型に関連付けられた名前を持ちます。
例えば、カーネル内でこのように使用します。
.Bd -literal
void function(int fd);
.Ed
.Pp
ユーザランドのアプリケーションに対して見えるヘッダファイルの中では、
可視のプロトタイプは、
型を伴った
.Dq 保護された
(アンダスコアで開始する) 名前を使用するか、
型だけで名前を使用しないかのどちらかが必要です。
保護された名前の使用がより望ましいです。
例えば、このように使用します。
.Bd -literal
void function(int);
.Ed
.Pp
または
.Bd -literal
void function(int _fd);
.Ed
.Pp
プロトタイプは関数名の行揃えを行なうために、タブの後に追加のスペース文字を
置いても構いません。
.Bd -literal
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;
.Ed
.Pp
一貫性のために、オプションの解析には
.Xr getopt 3
が使用されるべきです。
.Xr getopt 3
呼び出しと
.Ic switch
文では、オプションをソートすべきですが、
.Ic switch
文のカスケードの一部の場合は例外です。
.Ic switch
文のカスケード要素は
.Li FALLTHROUGH
コメントを持つべきです。
数値の引数は精度をチェックされるべきです。
到達できないコードは
.Li NOTREACHED
コメントを持つべきです。
.Bd -literal
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 != '\e0') {
warnx("illegal number, -n argument -- %s",
optarg);
usage();
}
break;
case '?':
default:
usage();
/* NOTREACHED */
}
argc -= optind;
argv += optind;
.Ed
.Pp
予約語
.Pq Ic if , while , for , return , switch
の後にスペースを入れます。
何も伴わないかただ 1 つの文を伴う制御文は、ブレースを使用しません。
1 つの文が 複数行である文の場合には、これは許されます。
無限ループは
.Ic while
ではなく
.Ic for
で行ないます。
.Bd -literal
for (p = buf; *p != '\e0'; ++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);
.Ed
.Pp
.Ic for
ループの各部は空のまま残しても構いません。
異常に複雑なルーチンでない限りは、ブロックの中に宣言を置いてはなりません。
.Bd -literal
for (; cnt < 15; cnt++) {
stmt1;
stmt2;
}
.Ed
.Pp
インデントは 8 文字のタブです。
第 2 レベルのインデントは 4 文字のスペースです。
長い分を折り返す必要がある場合、オペレータを行末に置きます。
.Bd -literal
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;
.Ed
.Pp
空白文字を行末に追加してはいけません。
また、インデントを形成するためには、タブとその後にスペースのみを使用します。
タブが生み出す以上のスペースや、タブの前のスペースは使用しません。
.Pp
ブレースの終了と開始は
.Ic else
と同じ行に置かれます。
必要でないブレースは省いても構いません。
.Bd -literal
if (test)
stmt;
else if (bar) {
stmt;
stmt;
} else
stmt;
.Ed
.Pp
関数名の後はスペースを空けません。
コンマの後にはスペースを持ちます。
.Ql \&(
または
.Ql \&[
の後ろまたは
.Ql \&]
または
.Ql \&)
の前にはスペースを空けません。
.Bd -literal
error = function(a1, a2);
if (error != 0)
exit(error);
.Ed
.Pp
単項演算子はスペースを要求しませんが、二項演算子は要求します。
優先順位が要求する場合または文が括弧なしでは混乱する場合以外は、
括弧は使用しません。
他人はあなたよりも混乱しやすいかもしれないということを覚えておいてください。
あなたは以下を理解できますか?
.Bd -literal
a = b->c[0] + ~d == (e || f) || g && h ? i : j >> 1;
k = !(l & FLAGS);
.Ed
.Pp
成功時には 0 で、または
.Xr sysexits 3
にあらかじめ定義してある値で exit するべきです。
.Bd -literal
exit(EX_OK); /*
* "Exit 0 on success." (成功時は 0 で終了)
* の様に明白なコメントは避けてください
*/
}
.Ed
.Pp
関数の型は、関数自身に先行する行にあるべきです。
.Bd -literal
static char *
function(int a1, int a2, float fl, int a4)
{
.Ed
.Pp
関数の中で変数を宣言する時には、サイズ順に、次にアルファベット順に
ソートして宣言します。
1 行に複数の宣言は可能です。
行が溢れる場合は、型の予約語を再度使用します。
.Pp
宣言時に変数を初期化することによってコードを
不明瞭にしない様に注意してください。
この機能は良く考えて使用してください。
初期化に関数呼び出しを使用しないでください。
.Bd -literal
struct foo one, *two;
double three;
int *four, five;
char *six, seven, eight, nine, ten, eleven, twelve;
four = myfunction();
.Ed
.Pp
他の関数の内部で関数を宣言しないでください。
ANSI C によると、このような宣言は、宣言のネスティングによらず、
ファイルスコープになります。
ローカルスコープに見えるものの中にファイルの宣言を隠すことは好ましくなく、
良いコンパイラは苦情を言います。
.Pp
キャストと
.Ic sizeof
演算子の後にはスペースを続けません。
この規則は
.Xr indent 1
が理解しないことに注意してください。
.Pp
.Dv NULL
は、好まれるヌルポインタ定数です。
コンパイラが型を知っている文脈、例えば代入では、
.Vt ( "type *" ) Ns 0
または
.Vt ( "type *" ) Ns Dv NULL
の代わりに、
.Dv NULL
を使用します。
他の文脈では、特に全ての関数の引数では、
.Vt ( "type *" ) Ns Dv NULL
を使用します。
(関数のプロトタイプがスコープ外かもしれない場合に、
キャストはいろいろな引数にとって必須で、その他の引数にとっても必要です。)
ポインタは
.Dv NULL
と比較します。例えば、
.Bd -literal
!(p = f())
.Ed
.Pp
ではなく、このように使います。
.Bd -literal
(p = f()) == NULL
.Ed
.Pp
真理値ではない場合、テストには
.Ic \&!
を使用しないでください。
例えば、下記のように使います。
.Bd -literal
if (*p == '\e0')
.Ed
.Pp
下記のようには使いません。
.Bd -literal
if (!*p)
.Ed
.Pp
.Vt "void *"
を返すルーチンでは、
戻り値をどのポインタ型にもキャストしてはなりません。
.Pp
.Xr err 3
または
.Xr warn 3
を使用し、勝手に作らないでください。
.Bd -literal
if ((four = malloc(sizeof(struct foo))) == NULL)
err(1, (char *)NULL);
if ((six = (int *)overflow()) == NULL)
errx(1, "number overflowed");
return (eight);
}
.Ed
.Pp
古いスタイルの関数宣言はこのようになっています。
.Bd -literal
static char *
function(a1, a2, fl, a4)
int a1, a2; /* int 型も宣言します、デフォルトにしないこと */
float fl; /* double と float の違いに気を付けてください */
int a4; /* 出てきた順に宣言します */
{
.Ed
.Pp
あなたが明確に K&R との互換性を必要とする場合以外は、
ANSI の関数宣言を使用してください。
長いパラメータリストの折り返しには、
4 個の空白による通常のインデントを付けます。
.Pp
可変個数の引数はこのようにします。
.Bd -literal
#include <stdarg.h>
void
vaf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
STUFF;
va_end(ap);
/* void 型の関数に return は不要です */
}
static void
usage()
{
/* 関数がローカル変数を持たない場合、空行をいれます */
.Ed
.Pp
.Xr fputs 3 ,
.Xr puts 3 ,
.Xr putchar 3
等ではなく、
.Xr printf 3
を使用してください。
これは速くて大抵はきれいで、言うまでもなくつまらないバグを避けます。
.Pp
使用法 (usage) の文はマニュアルページの
.Sx SYNOPSIS
(書式) の様であるべきです。
使用法の文は、次の構造であるべきです:
.Bl -enum
.It
オペランドの無いオプションが、最初にアルファベット順に、
1 組の大括弧
.Ql ( \&[
.Ql \&] )
でくくられます。
.It
オプションとそのオペランドがこれもアルファベット順に続き、
それぞれのオプションとその引数を 1 組の大括弧でくくります。
.It
必須の引数
(もしあれば)
が続き、
コマンドラインで指定されるべき順で一覧されます。
.It
最後に、
すべての任意の引数が指定されるべき順で、
すべて大括弧の中に一覧されます。
.El
.Pp
縦棒
.Pq Ql \&|
は、
.Dq 二者択一
のオプションまたは引数を分割し、
同時に使用するオプションと引数は、単一の大括弧でくくります。
.Bd -literal -offset 4n
"usage: f [-aDde] [-b b_arg] [-m m_arg] req1 req2 [opt1 [opt2]]\en"
"usage: f [-a | -b] [-c [-dEe] [-n number]]\en"
.Ed
.Bd -literal
(void)fprintf(stderr, "usage: f [-ab]\en");
exit(EX_USAGE);
}
.Ed
.Pp
マニュアルページのオプション記述は、
純粋なアルファベット順であるべきであることに注意してください。
つまり、オプションが引数を取るか否かに関わらないということです。
アルファベット順は、前述の大文字小文字の順序を考慮に入れるべきです。
.Pp
新しい中心的なカーネルのコードは、適度に
.Nm
ガイドに従うべきです。
サードパーティが保守するモジュールやデバイスドライバのためのガイドラインは
より緩やかですが、最低限内部的には彼らの一貫したスタイルであるべきです。
.Pp
ソースリポジトリの文体の変更 (空白文字の変更を含む) は困難で、
正当な理由なしには避けるべきです。
リポジトリの中のおおよそ
KNF
.Nm
に適合しているコードは、この適合から離れてはなりません。
.Pp
可能な時にはいつでも、
コードはコードチェッカ (例えば、
.Xr lint 1
または
.Nm gcc Fl Wall
) を
通過し、発生する警告は最小限となるべきです。
.Sh 関連項目
.Xr indent 1 ,
.Xr lint 1 ,
.Xr err 3 ,
.Xr sysexits 3 ,
.Xr warn 3
.Sh 歴史
このページは
.Bx 4.4 Lite2
リリースの
.Pa src/admin/style/style
ファイルに大きく基づいていて、
現在の実装と
.Fx
プロジェクトの要望を反映して、頻繁に更新しています。