コーディングスタイルとプログラムの品質

 コーディングスタイルは、好みの問題だという人がよくいます。
また一方で、それは品質に大きく影響するひとつの要素であることも否定できません。
すなわち、プログラマの好みがプログラムの品質に大きく影響し、何を好むかがプログラマの能力と直結するということです。

 コーディングスタイルというと、まず、ヘッダやコメントの記述,字下げ,改行など可読性に関わることが非常に重要な要素として挙げられまが、ここでは、それとは別に、バグを作らないためのちょっとしたテクニックを紹介したいと思います。


  1. 変数と定数を比較するときは、定数を左辺に

     定数と変数を比較するときに、

    if ( x == 0 ) {
    ... }

    のように、変数を左辺に,定数を右辺に記載するスタイルだと、

    if ( x = 0 ) {
    ... }

    のように、うっかり、= をひとつ書き忘れてもコンパイルエラーとはならず、実行時に何らかの不具合が発生するまでわからないことになります。
    これを、

    if ( 0 == x ) {
    ... }

    のように、定数を左辺に,変数を右辺に記載するスタイルにすると、

    if ( 0 = x ) {
    ... }

    のように、うっかり、= をひとつ書き忘れてしまった場合にはコンパイルエラーとなり、すぐにわかります。


  2. {} を省略しない

     if 文等を記載するときに、その配下のコードが単文の場合、

    if ( 0 == x )
    hoge();

    のように、{} を省略する人がいます。
    これだと、hoge() が複数の文からなるマクロだったりしたときは、意図通りのコードとならないことがあります。

    また、このような書き方はバグの元になります。

    ※ このことは、Sun の Java のコーディング規約でも注意事項として指摘されています。

  3. { の位置

     if 文を記載するときに、

    if ( 0 == x )
    {
    ... }

    のように、{if とは別の行に記載するスタイルだと、

    if ( 0 == x ) ;
    {
    ... }

    のように、うっかり、行末に ; を付けてしまってもコンパイルエラーとはならず、実行時に何らかの不具合が発生するまでわからないことになります。

    if ( 0 == x ) {
    ... }

    のように、{if と同じ行に記載するスタイルにすると、余計な ; を付けてしまうミスも起こりづらくなるでしょうし、

    if ( 0 == x ) { ;
    ... }

    のように付けてしまっても実害はありません。


  4. ( ) による演算順の明示化

     演算の順序を言語仕様の規定の順番に頼らず、( ) を使って明示的に記述することはバグの回避につながります。

    ※ このことは、Sun の Java のコーディング規約でも推奨する慣習として明記されています。


  5. { } によるブロック化

     Cの場合、変数は関数の最初に宣言しなけらばならないので、大きな関数になってしまった場合、変数の管理が大変です。
    ところが、実はこれは「関数の先頭」ではなく「ブロックの先頭」なのです。
    そこで、大きな関数は、{ } でいくつかのブロックに区切って、局所的にしか使わない変数は、そのブロック内で宣言すればソースが見やすくなります。

    以下は、ひとつの関数の中に局所的なブロックを作った例ですが、ここで、i の使い方間違いではありません。
    i は、ブロック内とブロック外で別物となります。

    void func()
    {
    int i;

    i = sqrt(144);
    {
    int i;

    for ( i=0; i<10; i++ ) {
    ...
    }
    }
    fprintf(stderr, "sqrt(144) = %d\n", i);
    }


  6. if ( !strcmp(s1, s2) ) { ... } はやめよう

     strcmp() の戻り値は BOOL値 ではありません、従って、杓子定規なことを云えば標記のコードは正しくありません。
    しかし、実際問題として、このことによって不都合が発生することはないと思います。

    ここで問題にしたいのは、「!」が持つネガティブなイメージが、「 if ( !strcmp(s1, s2) ) { ... } は、s1 と s2 が等しくないとき」という間違いを引き起こすことです。
    徹夜が続いたときなとは、思わずやらかしてしまいそうです。

    strcmp() に限らず、C言語では BOOL値 を返すような関数はありません。
    関数の仕様に従った戻り値と比較して真偽の判定をすべきだと思います。


  7. 定数マクロより定数変数を使う(TIPS)

     定数を定義するときには、

    #define MAX 10

    と定義するよりも、

    const int MAX = 10;

    とした方が、正しくない使い方をしたときにコンパイルエラーとなり、バグが回避される場合があります。
    (どちらもコンパイル時に定数に置き換えられますが、const で変数を初期化した場合は使用箇所での型チェックが行われます。)