第39回
プログラミングの周辺事項(2)~きれいでわかりやすいソースとは?

3.複数の処理をできるだけ1行にまとめる

一般的には、1つの処理は1つの処理として明確に切り分ける方が、何をしているかがわかりやすくなります。しかし、Cでは複数の処理を1行にまとめてしまうことでソースコードをコンパクトにでき、それが定番となっています。

異なる処理は分けた方がわかりやすいが……

1つの処理を1行として、できるだけ分割する方がわかりやすいものです。たとえば、本コラムの「第37回 ファイルの扱い(2)~ファイル操作の実例」で取り上げたfopen関数を使ったファイルのオープン処理も、以下のような形にした方が理解しやすいはずです。

fp = fopen("abc.txt", "r");    /* ファイルをオープン */
if (fp  == NULL) {             /* オープンエラーの場合 */
  printf("Can not open file.¥n");
} else {
    :
}

上記のようにすれば、

(1)"abc.txt"を読み取りモードで開いてファイルポインタを変数fpに代入する。
(2)fpがNULLの場合はエラーメッセージを表示する。

……という処理構造が明確になります。

Cでは1つにまとめるのが定番

しかしCでは、この2行の処理を以下のように1行にまとめるのが通例になっています。

/* ファイルをオープンしてエラーか否かを調べる */
if ((fp = fopen("abc.txt", "r")) == NULL) {
  printf("Can not open file.¥n");
} else {
    :
}

さらに、=と==の記述ミスによるバグを防ぐため、第37回では以下のような書き方も紹介しました。

if (NULL == (fp = fopen("abc.txt", "r"))) {
  printf("Can not open file.¥n");
} else {
    :
}

分けるとややこしくなる場合もある

ほかにも、forやwhileの条件式の中で「ファイルなどから1行、あるいは1文字を受け取る処理」を記述して1行にまとめる書き方も一般的です。

たとえば「1行を受け取り、その結果がNULLでなければ続けて処理をする」といった場合、以下のように2行に分けると非常にややこしくなります。

buf = fgets(buf, _BUFSIZE, fp);
while (buf != NULL) {
    :
  buf = fgets(buf, _BUFSIZE, fp);  ------- ここでもう一度入力が必要になる
}

入力処理を条件式に組み込んで1行にまとめれば、非常にすっきりしたソースとなります。

while ((buf = fgets(buf, _BUFSIZE, fp)) != NULL) {

これらはCの慣習であり、慣れてしまえば「1行を読み込んで結果をbufに渡し、それがNULLでなければ……」と読み取ることは簡単です。

どのような場合でも、

関数呼び出しの戻り値を
分岐(if)や繰り返し(for、while)の条件式に使い
関数の呼び出しとその結果の判断を1つにまとめる

という形で用いられます。