動的に全てのデータ構造を確保することによって、ファイル名、行、ファイル、 シンボルを含む、いかなるデータ構造の長さや数についても、勝手な 制限を避けなさい。 ほとんどのUnixユーティリティでは、“長い行は黙って切り詰める”。 これはGNUユーティリティでは許容できない。
ファイルを読むユーティリティはNUL文字や、0177以上のコードを持つ 文字を含むあらゆる他の印字できない文字も、落とすべきではない。 唯一意味のある例外は、そういった文字を扱えない、ある種のプリンタへのイ ンターフェースを特別に意図したユーティリティだろう。 可能な限りいつでも、UTF-8やその他のエンコーディングを使って、 多バイト文字を表すバイト列を適切に扱えるようにしなさい。
エラーを無視したいと思っているのでなければ、あらゆるシステムコールのエ
ラーを確認しなさい。失敗したシステムコールから発生するあらゆる
エラーメッセージに、もしあればファイルの名前とそのユーティリティの名前
だけでなく、(perror
や同等のものから得られる)システムエラー文字
列を含めなさい。単なる“cannot open foo.c”や“stat failed”は十分でな
い。
malloc
やrealloc
のすべての呼び出しを、ゼロを返したかどう
か確認しなさい。例えそのブロックをもっと小さくしようとしていても、
realloc
の確認をしなさい。2の階乗にブロックサイズを丸めるシステム
では、realloc
はもっと小さい領域を要求する場合に異なるブロックを
得ることがある。
Unixでは、realloc
がゼロを返す場合、記憶領域を破壊してしまう。
GNU realloc
はこのバグを持たない。失敗すると、元のブロックは変更
されない。そのバグは直っているとみなしても構わない。もしあなたのプログ
ラムをUnix上で走らせたくて、こういう損失を避けたいなら、GNU malloc
を使うことができる。
free
は解放されたブロックの中身を変えてしまうと考えなければなら
ない。そのブロックの値を取り出したかったら、必ずfree
を呼ぶ前に
取り出さなくてはならない。
もしmalloc
が対話的でないプログラムで失敗したら、それを致命的な
エラーにしなさい。対話的なプログラム(ユーザからコマンドを呼んでくるも
の)では、そのコマンドを中止して、コマンド読み込みループから返るのがよ
り良い。こうすると、そのユーザは仮想メモリを解放するために他のプロセス
を殺して、再びそのコマンドを試すことができる。
もし引数の文法が上手く行かなくなるわけでないなら、引数の解読に
getopt_long
を使いなさい。
静的な記憶領域がプログラムの実行中に書き込まれるためであるとき、それを 初期化するための、明示的なCのコードを使いなさい。変更されないデータに 対する、Cの初期化付き宣言を残しておきなさい。
(ファイルディレクトリや、utmp、カーネルメモリの配置のような)Unixのデー
タ構造を見えにくくする、低水準のインターフェースを避けるよう努めなさい。
これらは互換性を失いがちだからだ。もしあるディレクトリの全ファイルを見
付ける必要があるなら、readdir
や他の高水準のインターフェースを使
いなさい。これらはGNUによって互換性を持ってサポートされるだろう。
好ましいシグナルハンドリングの機能はBSD流のsignal
と
posix sigaction
関数である。別にあるUSGのsignal
は
劣った設計だ。
今日では、posixシグナル関数の使用がプログラムを移植しやすくする
一番簡単な方法かもしれない。signal
を使うと、GNU libc version 1
を使うGNU/Linuxシステム上でBSDの振る舞いを得るために、signal.h
ではなくbsd/signal.hをincludeすべきだ。signal
がUSGの振る
舞いしか持たないシステムをサポートするか、あるいは、それらを諦めてしま
うかはあなた次第だ。
“あり得ない”状態を検出するエラーチェックでは、単に中止しなさい。メッ セージを出力する意味は普通ない。これらのチェックはバグの存在を示している。 そのバグを直したい人なら誰でも、そのソースコードを読み、デバッガを走ら せないといけないだろう。だから、そのソースにコメントでその問題を説明し なさい。関係のあるデータは変数の中で、それはデバッガで検査するのは容易 だろう。だから、それらをどこか他の位置に移す意味はない。
プログラムの終了状態として、エラーのカウントを使ってはならない。 これは上手く行かない。なぜなら、終了状態の値は(0から255までの) 8ビットに制限されているからだ。そのプログラムが一回走る間に256のエラー が起きるかもしれない。もし終了状態として256を返そうとすると、親プロセ スはその状態として0を見ることになり、そのプログラムが成功したかのよう に見えるだろう。
もし一時ファイルを作るなら、TMPDIR
環境変数を確認しなさい。この
変数が定義されていれば、/tmpではなく、指定されたディレクトリを
使いなさい。