/* $NetBSD: style,v 1.14 2000/03/10 12:46:30 lukem Exp $ */ /* * 1行目にリビジョンコントロールタグ、その後に空行。 * その次に著作権関係の文章が来る。 */ /* * NetBSD ソースコードスタイルガイド * (以前よりKNF - Kernel Normal Form として知られている) * * from: @(#)style 1.12 (Berkeley) 3/18/94 */ /* * このドキュメントに沿ったスタイルに近い indent(1) 用プロファイルが * /usr/share/misc/indent.pro にある。コードをKNFに変換する際に手助けとなる * 役立つツールであるが、このプロファイルの使用による indent(1) の出力を * 権威あるリファレンスとしては考えてはならない。 */ /* * いくつかの著作権関係文章の後にソースコードのリビジョンコントロール * 識別子が来る。<sys/cdefs.h>から適切なマクロを使用する。通常 * プログラムにつき一つのソースファイルだけに __COPYRIGHT() セクションが * 含まれる。また歴史的なバークレーコードは __SCCSID() セクションを * 持つ場合がある。これらのマクロは各行にそれぞれ一つだけ置いて良い。 */ #include <sys/cdefs.h> #ifndef __lint __COPYRIGHT("@(#) Copyright (c) 2000\n\ The NetBSD Foundation, inc. All rights reserved.\n"); __RCSID("$NetBSD: style,v 1.14 2000/03/10 12:46:30 lukem Exp $"); #endif /* !__lint */ /* * 非常に重要な一行コメントはこのようにする。 */ /* 多くの一行コメントはこのようにする。*/ /* * 複数行のコメントはこのようにする。本物の文章にする。 * ここが本物の段落に見えるように文章をうめる。 */ /* * 80文字以上の行は適切に折り返す。 * 詳細は下に続く例を参考に。 */ /* * ヘッダファイル例: * * ヘッダファイルは多重インクルードに対して自らを保護しなければならない。 * たとえば、<sys/socket.h>は次のような行を含んでいるだろう。 */ #ifndef _SYS_SOCKET_H_ #define _SYS_SOCKET_H_ /* * 多重にインクルードされれば #include ファイルの中身の #ifndef と * 最後の #endif との間は飛ばされることになる。 */ #endif /* !_SYS_SOCKET_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 のインクルードファイルへと続く。 * /usr のインクルードファイルはソートされていなければならない! */ #include <stdio.h> /* * グローバルなパス名は /usr/include/paths.h で定義されている。プログラムに * ローカルなパス名はローカルディレクトリの pathnames.h に入れる。 */ #include <paths.h> /* それから、空行を置き、ユーザーのインクルードファイルとなる。 */ #include "pathnames.h" /* ローカルなものはダブルクオートで囲む。 */ /* * プライベートな関数(すなわち、どこか他で使用されない関数)のANSI関数宣言と * main()関数をソースモジュールの先頭にもっていく。 * 型に名前を連結させない。すなわち、次のようにする: * void function(int); * 関数の型と名前の間のインデントと、一行よりも長いプロトタイプの折り返し方法 * については、あなた自らの判断で行うこと。後者の場合、最初の左括弧の下に * 一列に並んでいるとより読みやすいかもしれない。 * いずれにせよ、一貫性が重要である! */ static char *function(int, int, float, int); static int dirinfo(const char *, struct stat *, struct dirent *, struct statfs *, int *, char **[]); static void usage(void); int main(int, char *[]); /* * マクロは大文字にして、括弧で囲み、副作用を避けなければならない。 * もし関数のインライン展開であるならば、その関数はすべて小文字で定義し、 * そのマクロは同じ名前ですべて大文字にする。もしマクロが式であるならば、 * その式を括弧で囲む。もしマクロが一つのステートメントよりも多ければ、 * 続くセミコロンが働くように“do { ... } while (0)”を使う。 * 読みやすくするためにバックスラッシュを右揃えにする。 * CONSTCOND コメントは lint(1) を納得させるためのものである。 */ #define MACRO(v, w, x, y) \ do { \ v = (x) + (y); \ w = (y) + 2; \ } while (/* CONSTCOND */ 0) #define DOUBLE(x) ((x) * 2) /* Enum型は大文字にする。最後の要素にはコンマを付けない。 */ enum enumtype { ONE, TWO } et; /* * 構造体での変数の宣言では、コンパイラでのアラインメントによるメモリの無駄を * 最小にすることを元に、次にサイズ、そしてその次にアルファベット順に、並び * 組み立てて宣言する。たとえば“int a; char *b; int c; char *d”とはせずに * “int a; int b; char *c; char *d”とする。 * すべての変数はそれ自身の型と行を持っているが、ビットフィールドを宣言する * ときは(それが一つのビットフィールドであること明確にするために)例外を作 * ることができる。一般にビットフィールドの使用は反対されていることに注意す * ること。 * 主な構造体は使用されるファイルの先頭で、もしくは複数のソースファイルから * 使用される場合は分離されたヘッダファイルで、宣言されていなければならない * もしヘッダファイルで宣言される場合は、構造体の使用は別々の宣言とならなけ * ればならず、かつ "extern" となっていなければならない。 * * 各メンバの名前に意味のある接頭語を使うことが役に立つこともあるだろう。 * たとえば“struct softc”ならば“sc_”という接頭語というように。 */ struct foo { struct foo *next; /* 使用中の foo のリスト */ struct mumble amumble; /* mumble へのコメント */ int bar; unsigned int baz:1, /* ビットフィールド; 望むなら一列でも */ fuz:5, zap:2; u_int8_t flag; }; struct foo *foohead; /* グローバルな foo のリストの先頭 */ /* typedefで構造体名を合わせる。 */ typedef struct BAR { int level; } BAR; /* * すべての主要なルーチンは、それらが何をするか簡単に説明されたコメントが * なければならない。"main"ルーチンより前にあるコメントは、そのプログラムが * 何を行うか説明されていなければならない。 */ int main(int argc, char *argv[]) { long num; int ch; char *ep; /* * 一貫性のため、オプションの解析にはgetoptを使用しなければならない。 * オプションはswitchの縦続部分を除いて、getoptの呼び出しと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') errx(1, "illegal number -- %s", optarg); break; case '?': default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; /* * キーワード(while, for, return, switch)の後にはスペースを入れる。 * 長いステートメントでない限り、一つのステートメントもしくは何もない * コントロールステートメントに括弧は使用しない。 * * 無限ループには while ではなく for を使用する。 */ for (p = buf; *p != '\0'; ++p) continue; /* 明示的な no-op */ for (;;) stmt; /* * for ループの部分は空のままにされる場合がある。 * ルーチンが異常に複雑にならない限り、ブロックに宣言を入れない。 */ for (; cnt < 15; cnt++) { stmt1; stmt2; } /* 二段目のインデントは4つのスペースを使う。 */ while (cnt < 20) z = a + really + long + statment + that + needs + two lines + gets + indented + four + spaces + on + the + second + and + subsequent + lines; /* * 閉じ括弧と括弧は同じ行に。 * 曖昧さまたは読みやすさに問題があるところ以外で必要の無い括弧を * 入れない。 */ if (test) { /* * 長いコメントをここに入れる。 */ #ifdef zorro z = 1; #else b = 3; #endif } else if (bar) { stmt; stmt; } else stmt; /* 関数名の後にスペースを入れない。 */ if ((result = function(a1, a2, a3, a4)) == NULL) exit(1); /* * 単項はスペースを必要とせず、二項では必要とする。 * 過剰に括弧を使用しない、しかし、次のようにもし括弧がなければ * 本当に混乱するようなステートメントには使用するべきである: * a = b->c[0] + ~d == (e || f) || g && h ? i : j >> 1; */ a = ((b->c[0] + ~d == (e || f)) || (g && h)) ? i : (j >> 1); k = !(l & FLAGS); /* * 成功時には 0 で、失敗時には 1 で終了する。複数ある exit() を * 識別するために、1〜300などの整数を使ったりするな。 * "成功時は 0 で終了"というようなわかりきったコメントは避ける。 */ exit(0); } /* * 関数の型はその前の行で宣言されなければならない。 */ static char * function(int a1, int a2, float fl, int a4) { /* * 関数中での変数の宣言ではサイズ順に、つぎにアルファベット順に * ソートし宣言する。一行に複数あっても良い。関数のプロトタイプは * "extern.h" インクルードファイルに入れるべきである。 * もし行が溢れるようであれば型キーワードを再利用する。 * * 宣言中で変数を初期化してはいけない。 */ extern u_char one; extern char two; struct foo three, *four; double five; int *six, seven; char *eight, *nine, ten, eleven, twelve, thirteen; char fourteen, fifteen, sixteen; /* * キャストとsizeofの後にはスペースを入れない。NULLは * どのポインタ型ともなりえ、キャストは必要無いので、 * (struct foo *)0 や (struct foo *)NULL のかわりに NULL を使用する。 * またNULLとポインタをテストする。すなわち * * (p = f()) == NULL * であり、次のものは使用しない。 * !(p = f()) * * boolean型以外のテストに `!' は使用しない。 * たとえば、"if (*p == '\0')" を使い、"if (!*p)" は使わない。 * * void * を返すルーチンはそれらの帰り値をどのポインタ型にもキャスト * してはならない。 * * err/warn(3) を使用し、自分で書いたものを使うな! */ if ((four = malloc(sizeof(struct foo))) == NULL) err(1, NULL); if ((six = (int *)overflow()) == NULL) errx(1, "Number overflowed."); return (eight); } /* * ANSI関数宣言を使用する。ANSI関数の括弧は古いスタイル(K&R)関数の * 括弧のように見える。 * 折り返されたプロトタイプごとにあなたの判断で続く行を整形する。 */ static int dirinfo(const char *p, struct stat *sb, struct dirent *de, struct statfs *sf, int *rargc, char **rargv[]) { /* 関数がローカル変数を持っていないならば空行を入れる。 */ if (stat(p, sb) < 0) err(1, "Unable to stat %s", p); /* * 64ビット数のprintfには、%llと(long long)へのキャストを使用する。 */ printf("The size of %s is %lld\n", p, (long long)sb->st_size); } /* * 可変長の引数に対応した関数はこのようにするべきである。 * (他のインクルードファイルの先頭に #include <stdarg.h> が * 現れるようにする)。 */ #include <stdarg.h> void vaf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); STUFF; va_end(ap); /* void型関数にはreturnは必要無い。 */ } static void usage(void) { extern char *__progname; /* NetBSDのcrt0.oより与えられる */ /* * fputs/puts/putchar/などは使わず、printf(3)を使用する。 * それは速くて、より使いやすく、くだらないバグを避けられることは * 言うまでもない。 * またしてもくだらないバグを避けるため sprintf(3) のかわりに * snprintf(3)かstrlcpy(3)/strlcat(3)を使う。 * * Usageステートメントはマニュアルページに見えるようにするべきだろう。 * オペランドのないオプションが最初に来て、一つの括弧の組のなかで * アルファベット順に並べる。オペランドのあるオプションが続き、 * 各括弧ごとにアルファベット順に並べる。指定された順の必要な引数が * 続き、指定された順の任意の引数が続く。バー(`|')でオプションと * 引数を分け、一緒に指定される複数のオプションと引数は一組の括弧の * 中に配置する。 * * プログラム名をハードコードするかわりに __progname (crt0.oより) * を使用する。 * * "usage: f [-ade] [-b b_arg] [-m m_arg] req1 req2 [opt1 [opt2]]\n" * "usage: f [-a | -b] [-c [-de] [-n number]]\n" */ (void)fprintf(stderr, "usage: %s [-ab]\n", __progname); exit(1); }