コメントの書き方 | Programming Place Plus C言語編 第5章

トップページC言語編

このページの概要 🔗

以下は目次です。


コメントの書き方 🔗

ソースコードを読みやすくするために、大きな助けとなるのがコメント(注釈) (comment) です。コメントとは、ソースコードの中に記述するメモ書きのことです。日本語で自由に記述でき、プログラムの動作に影響を与えません。

【上級】コメントは、プログラムの実行には無関係であり無視されますが、より正確には、半角空白1文字に変換されます。そのため、たとえば ret/\*ここは無視\*/urn のような記述は、ret urn に変換されるため、return キーワードにはなりません。

ある程度大きなプログラムを書くようになると、どこでどんな処理をしているのか分かりにくくなってきます。プログラム内にコメントを入れておけば、後から処理を見直したときに、処理内容を思い出す助けになります。また、他人がプログラムを読み解くときに、理解の助けとしてもらう意味もあります。

コメントは2つの書き方があります。

1つは、/**/ という2文字の記号のペアで表現する方法です。これはこの後すぐに説明します。もう1つは、// という2文字で表現する方法です。これは、後程あらためて取り上げます

/**/ を使った方法では、この2つに挟まれた部分にメモを書き込めます。たとえば、次の例では3か所にコメントがあります。

/* 文字列の入力を受け取るプログラム */

#include <stdio.h>

int main(void)
{
    puts("Please enter the string.");
    char input_string[80];   /* 入力された文字列を受け取る変数 */
    fgets(input_string, sizeof(input_string), stdin);
    printf("%s", input_string);  /* fgets関数が改行文字も受け取っているので、2回改行されないように、\n を使っていない */
}

実行結果:

Please enter the string.
hello  <-- 入力された文字列
hello

コードを無効化するために使う 🔗

コメントになった部分は、プログラムの実行に影響を与えないので、一時的にコードの一部分を無効化するために使うことがあります。このように、処理の一部を無効化することを、コードをコメントアウト (comment out) する、ということがあります。

/* 文字列の入力を受け取るプログラム */

#include <stdio.h>

int main(void)
{
    /*puts("Please enter the string.");*/
    char input_string[80];
    fgets(input_string, sizeof(input_string), stdin);
    printf("%s", input_string);  /* fgets関数が改行文字も受け取っているので、2回改行されないように、\n を使っていない */
}

実行結果:

hello  <-- 入力された文字列
hello

puts関数の呼び出しをコメントアウトしたので、この部分は実行されなくなりました。いらなくなった処理を無効化する際、実際にソースコードの一部分を消してしまうと、当然、元に戻せなくなります。コメントアウトであれば、コメントとして残っているので、後から簡単に復元できます。

ただ、コメントアウトされたコードが大量に残っていると、見通しが悪くなります。復元の可能性がほとんど無くなった段階で、奇麗に削除してしまった方が良いかもしれません。

プログラムを、バージョン管理システムといったもので管理しているのなら、以前の状態に戻すことは容易なので、基本的に、いらないものは消しておくのが良いでしょう。バージョン管理システムについては、C言語の話題とは直接関係ないので、ここでは特に触れませんが、プログラミングをするにあたっては重要なツールですから、本格的にプログラミングを行うようになったら、導入することをします(学習段階でも十分価値があります)。

コメントの入れ子 🔗

ある構造の内側に、同じ形の構造が入っているような状態を、入れ子(ネスト、ネスティング) (nest、nesting) といいます。

コメントの場合、/**/ の内側に、さらにもう1組の /**/ が入っているような形は、コメントが入れ子になっているといえますが、これは許されません。

#include <stdio.h>

int main(void)
{
    /*
        コメント1
        /*
            コメント2
        */
        コメント3
    */
}

コメントの部分は色を変えて表現していますが、このように、最初に現れる /**/ とで1つのコメントとして扱われます。そのため、2つ目の /* は、コメントの内側にある単なる2つの文字に過ぎません。そして、最後の */ が余ってしまい、不正な文字があるとみなされて、コンパイルエラーになります。

//形式のコメント 🔗

コメントにはもう1つ、// を使った記法があります。// によるコメントは、// から、その行の行末までをコメントにします

// では、複数の行をまとめてコメントにできませんが、終端の記号を書く必要がありません。大抵のコメントは1行で完結するので、入力の手間を減らせます。

// 文字列の入力を受け取るプログラム

#include <stdio.h>

int main(void)
{
    puts("Please enter the string.");
    char input_string[80];   // 入力された文字列を受け取る変数
    fgets(input_string, sizeof(input_string), stdin);
    printf("%s", input_string);  // fgets関数が改行文字も受け取っているので、2回改行されないように、\n を使っていない
}

実行結果:

Please enter the string.
hello  <-- 入力された文字列
hello

/**/ によるコメントと比べて、どちらが優れているというものではありませんが、// のほうが手軽な感じはします。

文字列リテラル内のコメント記号

文字列リテラルの中に ///**/ が現れる場合、それはコメントをあらわす記号としては扱われません。文字列を構成する文字の並びであると認識されます。

#include <stdio.h>

int main(void)
{
    puts("Hello/*, World*/");
    puts("Hello, // World");
}

実行結果:

Hello/*, World*/
Hello, // World

一方で、/* によるコメントが、文字列リテラル内の */ によって終了されます。

#include <stdio.h>

int main(void)
{
    /*
    puts("Hello/*, World*/");
    */
    puts("Hello, // World");
}

このコードは実質は次のような状態なので、コンパイルエラーになります。

#include <stdio.h>

int main(void)
{
     ");
    */
    puts("Hello, // World");
}

コメントに書くこと・書かないこと

コメントには、後からソースコードを読む人(自分かもしれない)が、意味や意図を理解する助けになることを書くようにします。

目指すべきところは、「分かりやすくコメントを書くこと」ではなく、「コメントを書かなくても理解しやすいソースコードを書く」ことです。たとえば、変数につける名前を工夫することは、コメントに頼らずにソースコードを理解しやすくする有効な方法です。

ソースコードをみればすぐに分かることにまで、いちいちコメントを書く必要はありません。たとえば、次のプログラムのコメントの多くは不要なものです。

#include <stdio.h>    // stdio.h をインクルード

// main関数。ここから始まる
int main(void)
{
    puts("Please enter the string.");  // 入力を促すメッセージを出力
    char input_string[80];   // 入力された文字列を受け取る変数
    fgets(input_string, sizeof(input_string), stdin);  // 文字列の入力を受け取る
    printf("%s", input_string);  // fgets関数が改行文字も受け取っているので、2回改行されないように、\n を使っていない
}

この中でそれなりに価値があるのは、printf関数が改行していない理由を書いたコメントぐらいでしょう。

学習のときには、はじめて使った機能や文法がどういう意味であったかをメモしておきたい場合もあるでしょうから、有用とはいえないこれらのコメントを完全否定はしませんが、本格的な開発にまで持ち込まないほうがいいです。

コメントを書きすぎることには、次のようなデメリットがあります。

  1. 書き手は、ソースコードとコメントの整合性をずっと維持しなければならない
  2. 読み手は、ソースコードとコメントの両方を読む必要があり、労力が増す

1は、ソースコードを書いたときに同時に書き添えたコメントがあるとして、あとでソースコードを修正するときに、コメントが嘘にならないようにしなければならないという話です。厄介なことに、修正したソースコードから離れた場所に書いたコメントが影響を受ける可能性もありますから、コメントを書きすぎないことにも意味があります。

たとえば、変数を宣言する行に「この変数 x は、この後の計算式で使う」とコメントを書きました。その計算式はたしかに存在しましたが、あとになって不要になったので消すことになったとします。計算式があった行と、変数を宣言している行は離れていますが、このコメントを忘れずに修正できるでしょうか?

2は、ソースコードを理解する側の負担の問題です。特に、1が怠られていたときには更なる巨大な負担を与えます。つまり、ソースコードとコメントを見比べたときに、矛盾を見つけてしまったら、読み手はその違いの理由をなんとか理解しなければならなくなるということです。コメントは実行結果に影響しないのだから、ソースコードを信じるべきなのかもしれませんが、コメントに書かれている動作を目指してつくっていたはずが、ソースコードをそのように実装できていないのかもしれません。

ソースコードの読み手は、日本語で書かれたコメントがあると、ソースコードよりもコメントを優先して読み、コメントの記述を信じ込んでしまうこともあります。

書くといいコメントの例を挙げておきます。

  1. ソースファイルの概要を解説するコメントを、ソースファイルの先頭に書く
  2. 必要に応じて、ソースファイルの作者や連絡先の情報を、ソースファイルの先頭に書く
  3. 必要に応じて、ライセンス・利用規約に関する表記を、ソースファイルの先頭に書く
  4. ある程度の大きさをもった処理の集まりについて、その概要をその集まりの冒頭に書く
  5. 高度な専門知識や、あまり知られていない手法を使っている処理について、その参考になる書籍、URL、論文などを示す
  6. 作りかけになっているところや、改善が必要なところ、特定の環境(OS やコンパイラの種類・バージョンなど)に依存しているところを示す
  7. 単純に分かりづらいと感じるところを補足する
    • ただし、まずはソースコードを分かりやすくする工夫を凝らすべき


練習問題 🔗

問題① main関数をコメントアウトするとどうなるでしょう。

問題② 次のプログラムをコンパイルするとエラーになるでしょうか?(まず考えてから、試してください)

#include <stdio.h>

int main(void)
{
    /*
    char input_string[80];
        /*
        */
    /*/
    fgets(input_string, sizeof(input_string), stdin);
    printf("%s", input_string);
    */
}

問題③ 次のプログラムは正しいでしょうか。

#include <stdio.h>

int main(void)
{
    /*  puts関数に変えてみた
    printf("コメントは /* と */ で挟む\n");
    */
    puts("コメントは /* と */ で挟む");
}


解答ページはこちら

参考リンク 🔗


更新履歴 🔗

 第8章から練習問題⑫を移動してきて、練習問題③とした。

≪さらに古い更新履歴を展開する≫



前の章へ (第4章 入力と変数)

次の章へ (第6章 標準入力)

C言語編のトップページへ

Programming Place Plus のトップページへ



はてなブックマーク に保存 Pocket に保存 Facebook でシェア
X で ポストフォロー LINE で送る noteで書く
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー
先頭へ戻る