第二回 GNU C の書き方 (2)

変数の命名

変数名をどう付けるかは、割と意見の分かれる所であるように思う。 ここでは GNU でどうなのかに絞る。

とにかく小文字を使いなさい。 大文字は使わない方がいい。 なぜなら、マクロや列挙定数とごっちゃになり兼ねないからだ。 他にも、適当な接頭辞を使っているライブラリとコンフリクトさせないという効果もある。

だから、IgnoreHoge は良くない。 ignore_hoge とすべきだ。 また、 Emacs だとアンダースコアを区切りにした方が単語単位のコマンドを使えるので、大文字の区切りはあんまり良くないのだ。

そしてより重要なのは、分かりやすい名前を使うこと。 特に大域変数ではそうだ。 下手に安易な名前を使うと、後で意味が分からないし、他のところで名前がぶつかることがある。 それは避けるべきだ。

Linux の coding standard では、tmp のような変数名で何が悪い、という風に書かれているが、私も GNU もあまり良くないと思っている。 まあ非常に局所的な場面なら使ってもいいが、何をやりたいかを表していない名前というのは可読性を著しく損なってしまう。 例を挙げると、

   1 void
   2 swap (int *a, int *b)
   3 {
   4   int tmp = *a;
   5   *a = *b;
   6   *b = tmp;
   7 }

は、非常に有名なもので、特に問題はない。 しかしやっぱりこっちの方が後々のことを考えると良いと思う。

   1 void
   2 swap (int *a, int *b)
   3 {
   4   int old_a = *a;
   5   *a = *b;
   6   *b = old_a;
   7 }

関数名

関数名も基本的に変数名と同じである。 しかし変数と同じ規則だと紛らわしくなるので、少しは考えた方が良い。 個人的には、関数は動詞というか、アクションを意味する単語で始まる方が分かりやすいと思っている。

C プリプロセッサ

いわゆる cpp だが、こいつを使うのはなるべく避けた方が良い。 cpp で処理されると、 GDB で認識できなくなるのも問題だ。 それにマクロには副作用があることは誰でも知っているだろう。

まず定数に関して言うと、一般的にマクロよりも enum を使う方が良い。 マクロでないと #ifdef ... #endif が使えないではないか、と思うかもしれないが、それこそ悪いコードの見本だ。 Autoconf を使って調べる方が良い。 それに、enum の方が良いのは、それがどこで使うと意図されているかを明示できるからだ。 例えば、

   1 #define HDD_TOO_SMALL           0
   2 #define HDD_TOO_LARGE           1
   3 #define HDD_TOO_EXPENSIVE       2
   4 
   5 int hdd_error (void);

とあっても、コードを見ないとどこで使われているのやら分かりっこない (もちろん推測はできるが)。 だが、

   1 typedef enum
   2 {
   3   HDD_TOO_SMALL,
   4   HDD_TOO_LARGE,
   5   HDD_TOO_EXPENSIVE,
   6 }
   7 hdd_error_t;
   8 
   9 hdd_error_t hdd_error (void);

ならば、非常に分かりやすくなる。 それにこれならもはやマクロの真の値が重なっていないだろうか、などという、つまらん心配はしなくても済む。

次に関数っぽいマクロについて言えば、副作用を考えると、やはりちゃんと関数にした方がいい。 もし速度的な問題があるなら、インライン関数を使えば済むことである。 インライン関数については次回以降で説明しよう。

また、よく使われる #ifdef ... #endif の類だが、これにも多少規則がある。 もし HOGE が定義されているかどうかを調べたいなら、

   1 #ifdef HOGE
   2 ...
   3 #endif /* HOGE */

と書く。また、逆に定義されていないときなら、

   1 #ifndef HOGE
   2 ...
   3 #endif /* ! HOGE */

と書く。また、さらに中で入れ子にしちゃう場合は、

   1 #ifdef HOGE
   2 # ifdef BOO
   3 #  include <boo.h>
   4 # endif /* BOO */
   5 #endif /* HOGE */

のようにインデントを付けるのが流儀のようだが、これは一部のコンパイラではマズかったような気もする。 よく覚えていない。 GCC でちゃんと通るから、ここは良しとしよう。

ソースの構成

ソース全体に渡って、それが読みやすく、また、改造しやすくすることが極めて重要である。 また、ライセンスの問題もちゃんと考えなければならない。

当然のことだが、他のプログラムからソースを盗んでくる場合、ライセンスの問題を考えよう。 もし、それが copyleft なライセンス (例えば、 GPL LGPL ) なら、それを引き継がねばならない。 ここでは GNU について話しているのだから、当然あなたの書いたプログラムは GPL か LGPL にしたがっていることが多いだろう。 その場合、GPL や LGPL と適合しないライセンスのソースは絶対に使ってはならない。

ではまず、あなたのソースに必ず各ファイル毎に、一番上にライセンスの項目を入れよう。 そうしなければ法的に有効にならない可能性がある。 読む人が、各ファイルだけ見て、それがどういうライセンスなのか理解できるようにすることが望ましい。 GPL の場合の例を挙げる。

   1 /* hoge.c - the hoge facility */
   2 /*
   3  *  HOGE  --  Hoge hOge hoGe hogE
   4  *  Copyright (C) 2007  Free Software Foundation, Inc.
   5  *
   6  *  This program is free software; you can redistribute it and/or modify
   7  *  it under the terms of the GNU General Public License as published by
   8  *  the Free Software Foundation; either version 2 of the License, or
   9  *  (at your option) any later version.
  10  *
  11  *  This program is distributed in the hope that it will be useful,
  12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14  *  GNU General Public License for more details.
  15  *
  16  *  You should have received a copy of the GNU General Public License
  17  *  along with this program; if not, write to the Free Software
  18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  19  */

このように最初にそのファイルが何というファイルで、それがどういうことをやっているファイルなのかを入れておくと良い。 そして、そのプログラム名、正式な名前を書き、著作権者の項目を入れる。 この場合は GNU なので、Free Software Foundation, Inc. が著作権者となる。 著作権を法的に放棄するため、実際には copyright assignment などが必要になる。 しかしここでは触れないことにし、書き方の問題に絞ろう。

さて、その後は、まずヘッダをインクルードする。 もし Autoconf を使っているなら、config.h#include しないといけないかもしれない。 GNU ソフトウェアではよく system.h というヘッダを用意しておいて、それを #include することで、不要な #ifdef ... #endif の嵐を避けている。 詳しくは適当なプログラム (例えば、 Texinfo ) を参照して欲しい。

その後は大域変数の定義や宣言、関数の宣言が続き、その後は関数の定義が並ぶ、というのが普通である。 しかし、もし密接に関係した変数と関数の組み合わせがあるのなら、それを近くで定義しても構わない。 要は、読みやすいかどうか、書き直しやすいかどうか、なのだ。

そして論理的な区切りにはフォームフィード (C-l) を入れると良い。 こういう感じだ。

   1 /* global variables */
   2 /* hoge hoge */
   3 int hoge = 0;
   4 ^L
   5 
   6 /* functions */
   7 /* boo boo */
   8 int
   9 boo (void)
  10 {

それ以外にも、ファイルの名前付けやディレクトリの階層など、気を付ける点はたくさんあるが、それらはいずれ話すことにしたい。

まとめ

今回は名前の付け方やプリプロセッサ、構成方法に関して説明した。 次回は、GCC 特有の機能について述べてみようと考えている。 質問、意見、批判などは okuji at enbug dot org まで送って欲しい。


次の回 / 前の回 / はっきんぐ・うぃず・ぐにゅー に戻る。


Copyright © 1999,2000,2007 Yoshinori K. Okuji

Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.

HackingWithGnu/GnuStylePartTwo (last edited 2007-03-13 18:56:29 by YoshinoriOkuji)