ログ日記

作業ログと日記とメモ

カーネルコーディングスタイル

http://www.linux.or.jp/JF/JFdocs/kernel-docs-2.6/CodingStyle.html
via: http://d.hatena.ne.jp/takkan_m/20080413


これは楽しい。

Do not unnecessarily use braces where a single statement will do.

1つの文しか実行しないところに、必要のない括弧を使わないでください。

if (condition)
	action();

if ( 条件文 )
	action();

最近はCでもPHPでもずっとこのスタイル。目がこっちの方が見易くなってしまった。

C言語はスパルタ言語なのですから、それにふさわしく変数や関数を命名しまし
ょう。Modula-2 や Pascalプログラマとは違って、C言語プログラマは 「こ
の変数は一時的に使われるカウンターである(ThisVariableIsATemporaryCounter)」
などというような気のきいた名前は使いません。C言語プログラマは、"tmp" な
どの十分に書きやすく、それでいて少なくとも分かりにくくはならない変数名を
選ぶものです。

大文字小文字を混ぜたような名前は嫌がられますが、グローバル変数には、意味
のわかる名前が必要です。グローバル関数に "foo" などという無意味な名前を
付けることは不快感を与えてしまいます。

これがいつも不思議に思うところ。まぁ単語単位の操作はやりやすい。

もしローカル変数の名前付けに迷っているようなら、別な問題を抱えているもの
です。「関数成長ホルモン不均衡症候群」と呼ばれています。詳しくは第6章(
関数)を見てください。

"vps_t" のような定義は使わないでください。


It's a _mistake_ to use typedef for structures and pointers. When you see a

vps_t a;

in the source, what does it mean?

構造体やポインタに typedef を使うことが間違っています。ソース上で、
vps_t a;」という文を見たとき、どんな意味があると考えますか?

たまに野良モジュールのソースを見ると*_tが使われているから迷ったりする。が、使っては駄目なのか。

関数内のローカル変数の数も目安となります。ローカル変数は5〜10個にとど
めるべきもので、それを超えているようなら何か悪いことをしているのです。そ
ういう場合は関数を見直し、より細かく分割してください。一般的に、人間の脳
が余裕を持って同時に追えることは7つくらいが限界で、それ以上あると混乱し
てしまいます。自分の素晴らしさは自分が一番知っていることでしょう、がしか
し、2週間前に書いたものがすぐに分かると嬉しいとは思いませんか?

goto 構文の利用に否定的な人もいますが、コンパイラは goto 構文に等しい無
条件 jump 命令を頻繁に出力しているのです。

goto 構文は、関数がいくつかの場所で処理を終了してから共通的な動作(例え
ばクリーンアップ動作)を行う場合に重宝します。

Cなら普通にgoto使う。PHPにも欲しい。

一般的に、コメントでコードが何をしているのか(WHAT)を示そうとはしますが、
どうやっているのか(HOW)は示さないでしょう。また、関数の中にコメントを記
載することは避けましょう - 関数が複雑なので、別途に関数の説明コメントが必
要と考えるのであれば、第6章を読み直してください。「極めて巧妙なワザ(汚い
手ともいう)を使ったよ」と注意したい時にはちょっとしたコメントを付けても良
いですが、やりすぎないでください。それよりも、関数の先頭にコメントを付与し、
何をする関数なのか、さらに可能であれば、何故それをするのかまで示しましょう。

Linux カーネルにおけるコメントスタイルは、C89 の "/* ... */" スタイルです。
C99 スタイルの "// ..." のコメントは使用してはいけません。

これは開発中で未完成の場合に // でコメントして使い分けたりとか。

なので、GNU emacs の利用をやめるか、設定をまともにするかのどちらかです。
設定の見直しについては、ホームディレクトリの「.emacs」ファイルに次のよう
追記を行ってください -

(defun linux-c-mode ()
  "C mode with adjusted defaults for use with the Linux kernel."
  (interactive)
  (c-mode)
  (c-set-style "K&R")
  (setq tab-width 8)
  (setq indent-tabs-mode t)
  (setq c-basic-offset 8))

これで M-x linux-c-mode コマンドが定義されます。ソースファイルの先頭2行
のどこかに、「-*- linux-c -*-」という文字列を置いておけば、ハッキングする
際に、自動的に linux-c-mode になります。また、/usr/src/linux にあるソース
ファイルを編集する場合は自動的に linux-c-mode へ切り替えたいというのであ
れば、「.emacs」ファイルに

(setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.[ch]$" . linux-c-mode)
                       auto-mode-alist))

を加えてください。

なるほど。pathで場合分けするのか。早速使うことにする。
インデントにタブを使うんだねえ。

複数の文から構成されるマクロは do - while ブロックで囲むべきです。

#define macrofun(a, b, c) 			\
	do {					\
		if (a == 5)			\
			do_this(b, c);		\
	} while (0)

これはif文の後に処理が一つなら中括弧を付けないコーディングスタイルが元になっているからか。

カーネルメッセージはピリオドで終える必要はありません。

意外。

好ましい構造体サイズの渡し方は次のものです。

	p = kmalloc(sizeof(*p), ...);

これの代わりに構造体型の名前を記述する渡し方をすると、読みにくい事に
加え、ポインタ変数の型を変更した場合、メモリアロケータに渡すサイズが対応
しないバグの温床にもなります。

だいたいの経験則では4行以上の関数はインライン関数にしないことです。この
規則の例外は、引数がコンパイル時に定数であることがわかっている場合と、そ
れに伴いコンパイラの最適化によって関数の大部分が削除されると分かっている
場合です。例えば、後者の良い例が kmalloc() インライン関数でしょう。

関数は多くの異なる種類の値を返すことができ、最もありふれたの値の一つは関
数が成功したか失敗したかをを示す値です。そのような値はエラーコードの整数
値(-Exxx = 失敗、0 = 成功)か、「成功したかどうか」を表す boolean(0 = 失
敗、0 以外 = 成功)で表現されます。

この二つの表現が混在したソースには、見つけることの難しいバグが豊かに実り
ます。もしC言語が整数型と boolean 型を明確に区別してくれるなら、コンパイ
ラは私達のためにこれらのミスを見つけてくれるでしょう...しかし区別してくれ
ません。このようなバグを防ぐには、常に次のしきたりに従うことです -

もし関数の名前が動作か命令的な指示だったらその関数はエラーコード
として整数を返すべきです。もし名前が述部(条件の真偽を判定するよう
なもの)であればその関数は成功したかどうか」を表す boolean を返す
べきです。

例えば、"add work" は指示であり、そして add_work() 関数は成功時に0を返す
か、失敗時に -EBUSY を返します。同じように、"PCI device present" は述部で
あり、そして pci_dev_present() 関数は、対応するデバイスを見つけられたら、
1を返し、見つけられなかったら0を返します。

なるほど・・・。意識すると少しはコード探索しやすくなるかな。