C言語のコメントアウトは奥が深い

組み込み系の方とお話をした際に、C言語で記述する際のコメントアウトは基本/**/で
//を使わないというお話をお伺いしました。

その時は詳しく理由をお伺いできなかったのですが、気になってしまったので調べてまとめました。

もし間違っている箇所があればご教示お願いいたします。

//のコメントアウトはもともとC++のコメントアウト

私が学生時代に授業でC言語を習ったときはコメントアウトは2つあり、1行をコメントアウトする際は//を使い、複数行コメントアウトをする場合は/**/を使いましょうと習ったので、どちらもC言語のコメントアウトだと思っておりました。

しかし、下記本のP39ページに次のような記述がありました。

 プログラム中に処理の内容をメモする場合は、コメントアウトという機能を使用します。「/*」と「*/」で囲まれた文字列はコンパイル時に無視されるため、ここに任意の文字列を記述することができます。この中には日本語や全角文字、予約語などを記述 しても問題ありません。見やすいソースを作成するためにも、積極的にコメントを残すことが望ましいです。
 また、 「//」もコメントアウトとして利用できます。これはC++言語で採用されているコメントアウトですので、C言語では使用できない場合があります。が、本書で利用しているLPCXpressoでは利用可能です。

ARMマイコンによる組込みプログラミング入門 改訂2版: ロボットで学ぶC言語
ヴイストン, ロボット実習教材研究会
オーム社 (2018-05-09)
売り上げランキング: 164,583


なるほど... //はもともとC++のコメントアウトなんですね。
C言語で使えない場合があるということだったので、どんな時に使えないのか調べてみると古い規格だと使えないみたいです。
最近の処理系では、Cモードでのコンパイル時に、// をコメントとして使えますが、ANSI Cの定義に組み込まれるようになったのはC99の規格からです(C89の規格では//は定義されていません)。よって、処理系によっては使えない場合があるのでCプログラミングでは注意しましょう(C++では大丈夫です)。
 プログラミング演習ⅢC++ C言語との違いより引用

(C99の規格についてはこちらを参考にしてくださいC99)

個人利用の場合はC99以降の規格でコーディングをすることができるので、気にする必要がないですが、組み込み系の方は古い規格でコーディングしなければいけない場合があるので、確実に使える/**/を使ってると思われます。

簡単な実験

gccには規格を指定してコンパイルをするオプション?が存在します。
そちらを使って規格によってコンパイルエラーが起きることを確認します。
まずtest.cという名前で下記のファイルを作成します。
#include
void main(){
    //このコメントがあることでコンパイルエラーが起きるか確認
    printf("test\n");
}

そしてコマンドプロンプトにて下記コマンドを入力します。
こちらを実行することでC90という//のコメントアウトが導入される前の規格でコンパイルを行えます。
gcc .\test.c -std=c90

実行結果は次の通りです。
.\test.c: In function 'main':
.\test.c:3:5: error: C++ style comments are not allowed in ISO C90
    3 |     //
      |     ^
.\test.c:3:5: note: (this will be reported only once per input file)

エラーメッセージを見ると「C++形式のコメントはISO規格のC90ではサポートしていない」と出ています。

今回は結果は載せないですが、//のコメントアウトが導入されたC99の規格も試しました。
実行したコマンドは下記のとおりです。
gcc .\test.c -std=c99

特に問題なくコンパイルが通り、実行ファイルを実行するとtestと表示されました。

//を使うと"ダメ文字"の影響を受けてしまう場合がある。

C言語のコメントについて調べていたら下記のような記事がありました。

この記事がなかなか面白く、「このコメントを消すと動かないので、消しちゃダメ」というネタの仕組みを解説してくれています。

このコメントがないとコンパイルエラーが起きる理由として、Shift-JIS特有の"ダメ文字"というの影響があるそうです。

コメントアウトとして//を使った場合に行末にバックスラッシュが存在すると、その行の改行が無視されてしまい、次の行がコメントアウトされてしまいます。

Shift-JISは1文字当たり2バイトで表現され、2バイト目がバックスラッシュと同じ文字コード(0x5c)となっている文字をダメ文字といいます。
この文字がコメントの末尾に入っていると末尾にバックスラッシュが入っていると認識されてしまい、次の行がコメントアウトされてしまいます。具体的には”表”や”能”などです。

このダメ文字は//を使ったときのみなので、/**/を使えば回避することができます。

ダメ文字はバグの原因となり得てしまうので、それを回避するために組み込み系の人はコメントとして/**/を使っていると考えられます。

簡単な実験

//と/**/のコメントアウトの違いを簡単なコードを書いて実験してみます。
最初に//を使った場合の挙動を確認します。
#include
void main(){
    //このコメントがあると下の文字を表示することが不可能
    printf("test\n");
  printf("abc\n");
}
こちらのコードはコメントの末尾にダメ文字である"能"を使っています。
Shift-JIS形式でこのコードを保存して実行した結果がこちらです。
abc

ダメ文字を使ったコメントアウトの直下のprint文が実行されず、”test”という文字列が表示されていません。

次に/**/を使った場合の挙動です。
#include
void main(){
    /*このコメントがあると下の文字を表示することが不可能*/
    printf("test\n");
    printf("abc\n");
}

test
abc

こちらはコメントにダメ文字を使っていますが、きちんと処理が実行されています。

(補足)pythonの場合はどうなるか。

私は普段pythonを使っているので、pythonの場合はどうなるか試してみました。
pythonの場合は1行のコメントアウトは"#"となっております。
先ほどと同様にtest.pyという名前で下記のコードをShift-JIS形式で保存し実行します。
# このコメントがあると下の文字を表示することが不可能
print("abc")
print("test")

実行した結果下記のようなエラーメッセージが表示されました。
SyntaxError: Non-UTF-8 code starting with '\x89' in file .\test.py on line 1, 
 
but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

pythonはデフォルトではShift-JISで記述されたコードが実行できないみたいです。
下記のように1行目に文字コードを指定すると、Shift-JISで記述されたコードでも実行できるようになります。

# coding: shift_jis
# このコメントがあると下の文字を表示することが不可能
print("abc")
print("test")

実行結果は下記の通りでした。
abc
test

pythonの場合はShift-JISで記述されてもダメ文字の影響を受けないようになってることがわかります。

まとめ

たかがコメントアウトと思っていましたが、調べてみると奥が深かったです。

調べた結果組み込み系の人がコメントアウトで/**/を使ってい理由は下記2つだと思います。
①古い規格の場合、//が使えないのでどんな規格でも対応できる/**/を使用している。
②ダメ文字によるバグを回避することができる。

もし他にも理由があれば教えていただけると幸いです。

0 件のコメント :

コメントを投稿