アークピットのホームページに戻る

WinAPIトピックのトップページに戻る

APIトピックの各章に移動する

ダウンロードのページに移動する
ダウンロードができ
ない場合の対処法
 

ページ移動

1-2-7. C言語のスタイル

 C言語は、フリースタイルのプログラミング言語ですので、いろいろな書法があります。しかし、あまりに独自の書法では、個人として使用するのは良いのですが、グループで作成する時や、完成したソースコードを公開・提供する場合に困ったことになります。最近はオープンソースコードの運動も盛んです。ソースコードは非常に重要な資産ですので、その書法にもオープン性を取り入れ、ここでもう一度自分のスタイルについて考えてください。

スタイルの考慮点

  • コメントの書法
  • インデントとタブの扱い
  • {・}の位置
  • スペースの入れ方
  • switch文のスタイル
  • 関係演算子の左辺と右辺
 私たちは、C言語の書法は、まず「カーニハン&リッチの書式」を基本とします。その上で、上記の点ぐらいは、決めて置かなければいけません。

コメント

 コメントは、コードの一部と考えるべきです。自分で作成したコードでも3ヶ月も立つと(時には1週間で)、そのコードが何のためにあるのか、どういう役割をもつのか分からなくなることもあります。よって適切なコメントは絶対に必要な要素です。
 まず関数の先頭で、その関数の役割とパラメータの意味や用法をコメントで説明します。この場合は、すべての関数で書式を統一し、「適正」な分量にすべきです。ある大手のソフトウェア企業のコードを見たことがありますが、そこでは、コードよりコメントの方が多くの量を費やしてしました。またパラメータも関数の説明も1行で済ませる例もあります。よって「適正」な分量に定型はありません。作成者の用途や考えで異なります。私は、コンポーネントや他者に公開を予定する場合は増やします。その関数があちこちで使わないプライベートなものや、他との関連の薄い関数は1行だけのこともあります。

 コメントは行間にも記入します。関数内で、処理がいくつかに分離している場合は、その処理ごとにコメントを入れます。また用途の分かり難い文を解説することもあります。ただし以下の様なコメントはやめましょう。

    *p++ = 'A';  // ポインタpに文字「A」を設定する。
 これはCの文を説明しているに過ぎません。文を見れば分るような説明は必要ありません。ところでコメントは、// と /*・・・*/ の2つの書式がりますが、行間は // で、複数行に渡るコメントは /*・・・*/ の書式を普通は使用します。

インデントとタブ

 C言語では、インデントを多用しますので、タブは重要です。しかしタブは少し考えなくてはいけません。
 まずインデントの量の問題です。これは昔なら8文字でしょうか。しかし現在は4文字のことが多いと思います。1つの文は1行に記述するのが、コードを分かり易くします。よって多くのインデント量を取ると、少し深い文はスペースが不足しますので、4つぐらいが適当でしょう。
 次にタブです。これはハードタブとスペースで代用したソフトタブのどちらを使うかの問題です。これは一長一短ありますが、ソフトタブを推薦します。ハードタブは、1キーでインデントの挿入・削除が可能なので、便利です。しかし、インデントの量は昔のFortranの頃から8タブがデフォルトなので、別環境では思った表示ができません。
 さらに1行の文字数は、今なら自由ですが、印刷や別環境でも問題の少ない80文字をお勧めします。

{と}の位置

 C言語のスタイルで一番いろいろなスタイルがあるのがこの{・}の位置です。この位置は見易さか情報量かの観点と一貫性の2つの観点から少し考えたいと思います。
(A)	if (code > '0' && code <= '9'){
		f = ID_NUMBER; ...
	} else {
		f = ID_ETC; ...
	}

(B)	if (code > '0' && code <= '9')
	{
		f = ID_NUMBER; ...
	}
	else
	{
		f = ID_ETC; ...
	}
 皆さんは(A)と(B)のどちらのスタイルを使っているでしょうか。(A)は行が節約でき多くの情報を盛り込めます。(B)はより見易いコードになります。私はカーニハン&リッチが(A)だったので、最初はこの方法で記述していました。しかし現在は(B)を使っています。DOSの頃はソースコードは24行の表示がやっとでしたが、WIndowsになって40行以上を一度の表示できるのが変わった最大の理由です。ただ(B)のスタイルならすべて統一すべきでしょうか。
(A)	typedef struct {		enum {
		int  x,y:			ERR_NOT,ERR_NOTMEMORY,...
	} XYPOS;			};
		↓			↓
(B)	typedef struct		enum
	{			{
		int  x,y:			ERR_NOT,ERR_NOTMEMORY,...
	}			};
	XYPOS;
 enumは(B)に統一しました。しかしtypedefやstructは、XYPOSは、}の後に続けて記述しています。しかしできるだけ、スタイルの統一は重要です。

スペースの入れ方

 スペースの入れ方も決めた方が良いでしょう。以下の部位でスペースを入れるか入れないか決めておきましょう。
  • ifやwhileとカッコの間
  • {や}の前後
  • 関数のパラメータの間
 変数を列記する場合は、揃えた方が良いでしょうか。
(A)	INT x,y;
	LPRECT prc;
	LPCREATESTRUCT pcs;	

(B)	INT		x,y;
	LPRECT		prc;
	LPCREATESTRUCT	pcs;
 (A)と(B)はどちらが良いでしょうか。私は折衷方式を取っています。極端に長い型の場合は、1つだけインデントせずに、他はスペースでインデントして仮変数名を揃えます。

switch文のスタイル

 switch文は使う人によってインデントの方法が異なります。皆さんはどの方法を取っているでしょうか。
(A)	switch (*cmd) {
	case 'A': opt = AOPT; break;
	case 'B': opt = BOPT; break;
	default:  opt = ERROPT; break;
	}
(B)	switch (*cmd)
	{
	    case 'A': opt = AOPT; break;
	    case 'B': opt = BOPT; break;
	    default:  opt = ERROPT; break;
	}
 (A)はカーニハン&リッチの書法です。(B)は我々が使用しているスタイルです。またこの折衷のスタイルや、caseの中の書法も数々あります。

関係演算子の左辺と右辺

 if 文で変数と定数を論理演算(関係演算子で判断)する場合は、定数を左辺にして変数を右辺にすることがあります。
    char *p;

        :(他のコード)
    if (NULL == p)  // (A)定数が左辺
    {
        :(他のコード)
    }
    if (p == NULL)  // (B)定数が右辺
    {
        :(他のコード)
    }
 上記の(A)が定数を左辺にした例で、(B)が右辺にした例です。私は、通常(B)の方法を使っていますので、(A)には違和感があるのですが、(A)には1つ大きな利点があります。

 関係演算子と等値演算子は、==,!=,<,>,<=,>= などですが、== の等値演算子を = と間違って入力することがあります。長くプログラマをやっていれば、1度や2度は誰でも経験していると思います。困るのは、= としてもCの構文上はエラーにならないことです。

    char *p;

    if (p = NULL)  // (B)間違い
    {
        :(他のコード)
    }
 上記は間違った例ですが、Cの構文上は、pのポインタにNULLを代入し、それが0以外なら if の内部を実行します。この場合は、NULL(0)ですので、if 文が実行されることはありません。つまり文法上は間違いではありません。
 それで、定数を左辺にします。すると、if (定数 = 変数) となりますので、定数に変数を代入することはできないので、コンパイル時にエラーになります。よって間違いをすぐ訂正できます。

ページ移動