//を使わないというお話をお伺いしました。
その時は詳しく理由をお伺いできなかったのですが、気になってしまったので調べてまとめました。もし間違っている箇所があればご教示お願いいたします。
目次[非表示]
//のコメントアウトはもともとC++のコメントアウト
私が学生時代に授業でC言語を習ったときはコメントアウトは2つあり、1行をコメントアウトする際は//を使い、複数行コメントアウトをする場合は/**/を使うと授業で習いました。このようにC言語の授業で習ったためどちらのコメントアウトもC言語のコメントアウトだと思っておりました。
しかし、下記本のP39ページに次のような記述がありました。
ヴイストン, ロボット実習教材研究会
オーム社 (2018-05-09)
売り上げランキング: 164,583
オーム社 (2018-05-09)
売り上げランキング: 164,583
プログラム中に処理の内容をメモする場合は、コメントアウトという機能を使用します。「/*」と「*/」で囲まれた文字列はコンパイル時に無視されるため、ここに任意の文字列を記述することができます。この中には日本語や全角文字、予約語などを記述 しても問題ありません。見やすいソースを作成するためにも、積極的にコメントを残すことが望ましいです。
また、 「//」もコメントアウトとして利用できます。これはC++言語で採用されているコメントアウトですので、C言語では使用できない場合があります。が、本書で利用しているLPCXpressoでは利用可能です。
なるほど... //のコメントアウトはもともとC++のコメントアウトなんですね。
//のコメントアウトが使えないときがあるという事でどんな時にこのコメントアウトが使えないのか調べてみると古い規格だと使えないみたいです。
最近の処理系では、Cモードでのコンパイル時に、// をコメントとして使えますが、ANSI Cの定義に組み込まれるようになったのはC99の規格からです(C89の規格では//は定義されていません)。よって、処理系によっては使えない場合があるのでCプログラミングでは注意しましょう(C++では大丈夫です)。
プログラミング演習ⅢC++ C言語との違いより引用
(C99の規格についてはこちらを参考にしてくださいC99)
個人利用の場合は基本的に新しい規格でコーディングをすることができるので、気にする必要がないですが、組み込み系の方は開発環境によって古い規格でコーディングしなければいけない場合があると思うので、確実に使える/**/を使ってると思われます。
(2023/05/30 追記)
インターフェースの7月号を読んでいたら、組み込みシステムではC89(通称ANSI C)を今でも使われることがあるという記載がありました. 理由としてはシステムの製品寿命が長いのと過去の資産との互換性などの問題からという事です.
組み込みシステムではC99以前のC89, 通称ANSI Cが今でも使われていることがあります.これは組み込みシステムの製品寿命が長いこともあり, 過去の資産との互換性などの問題から必要とされることがあるからです. しかし, 今あたらにRTOSを作成するにあたっては, よほど古いマイコンをターゲットにしない限りC99で問題ないでしょう.
(インターフェース 2023年 7月号のP34より引用)
組み込みの人はC89を使う場合があるという事で、習慣的に/**/のコメントを使う場合が多いのかもしれないです。
古い規格(C90)で//を使ったコメントアウトが使えないか実験
gccには規格を指定してコンパイルをするオプションが存在します。
そちらを使って古い規格でコンパイルエラーが起きることを確認します。
まずtest.cという名前で下記のファイルを作成します。
#include stdio .h 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特有の"ダメ文字"というの影響があるそうです。
コメントアウトとして//を使った場合ですが、行末にバックスラッシュが存在すると、その行の改行が無視されてしまい、次の行がコメントアウトされてしまうという動作をします。
(詳細はこちらの記事を参照してください。C言語の行コメント内にバックスラッシュ(¥)を入れると次の行がコメントアウトされることがある)
私はエディタとしてVScodeを使用しているのですが、末尾にバックスラッシュが入っていると次の行がコメントアウトされているのが視覚的に分かります。(コメントアウトされている行が緑色になっており、for分のところまでコメントアウトされていることが分かります。)
末尾にバックスラッシュが入ったコメントの次の行もコメントアウトされているため、変数iが宣言されてないというエラーとfor分の}がmain文の}となっており、}が一つ余っているというエラーが出ています。
Shift-JISでは1文字当たり2バイトで表現されるのですが、2バイト目がバックスラッシュと同じ文字コード(0x5c)となっている文字があり、このような文字をダメ文字といいます。
このダメ文字がコメントの末尾に入っていると末尾にバックスラッシュが入っていると認識されてしまい、次の行がコメントアウトされてしまいます。
具体的には下記のようなものがあるみたいです。(この中で末尾によく使われるのは"能"とか"表"とかですかね?)
ソ噂浬欺圭構蚕十申曾箪貼能表暴予禄兔喀媾彌拿杤歃濬畚秉綵臀藹觸軆鐔饅鷭
だめ文字より引用
このダメ文字は//を使ったときのみなので、/**/を使えば回避することができます。
ダメ文字はバグの原因となり得てしまうので、それを回避するために組み込み系の人はコメントとして/**/を使っていると考えられます。
2種類のコメントアウトでダメ文字を使った場合の動作確認
//と/**/のコメントアウトの違いを簡単なコードを書いて実験してみます。
最初に//を使った場合の挙動を確認します。
#include <stdio.h> void main(){ //このコメントがあると下の文字を表示することが不可能 printf("test\n"); printf("abc\n"); }
上記コードはコメントの末尾にダメ文字である"能"を使っています。Shift-JIS形式でこのコードを保存して実行した結果がこちらです。
abc
ダメ文字を使ったコメントアウトの直下のprint文がコメントアウトされてしまったため、”test”という文字列が表示されていません。
次に/**/を使った場合の挙動です。
#include <stdio.h> void main(){ /*このコメントがあっても下の文字を表示することが可能*/ printf("test\n"); printf("abc\n"); }
test abc
こちらもコメントにダメ文字の"能"を使っていますが、きちんと処理が実行されています。
ここで参考文献にもあったコメントを消すと動作しなくなる例を再現してみます。
簡単なコードですが、1から10までカウントするコードです。こちらをShift-jis形式で保存して実行してみます。
#include <stdio.h> void main(){ //この処理があることで1から10まで数えることが可能 for(int i=1;i<=10;i++){ printf("%d \n",i); } }
このコードを実行すると下記のようなエラーが出力されます。
"message": "expected identifier or '(' before '}' token",
これは"}"の前に"{"が無いと認識されてしまい、出ているエラーです。
パット見"{"はあるので問題ないコードに見えますが、コメントの最後に"能"というダメ文字がありfor文の最初がコメントアウトされてしまいます。
なので、ダメ文字があるコメントの次の行にコメントを書くことにより、処理に関係ないコメントがコメントアウトされるので、コンパイルエラーを防ぐことが出来ます。
補足ですが下記のようにコメントを挿入することでコンパイルエラーが回避できます。
#include <stdio.h> void main(){ //この処理があることで1から10まで数えることが可能 //このコメントは消さないで、消すとバグる for(int i=1;i<=10;i++){ printf("%d \n",i); } }
(補足)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で記述されてもダメ文字の影響を受けないようになってることがわかります。
(参考)ダメ文字が影響していると思われる不具合例
最近出たゲームでキャラクターの名前にカタカナの"ソ"が入るとバグるというものがあったみたいです。(先ほどダメ文字の一覧で紹介した通り、"ソ"はダメ文字の一つです。)
【ドカポンキングダム コネクト不具合のお知らせ】
— ドカポン・シリーズ公式 (@dokapon_jp) April 13, 2023
現在、「ソ」が含まれる名前/アカウント名でゲームを開始すると不具合が発生しております。
例)
✕「ソーセージ」
〇「そーセージ」
詳細は引用ツイートをご確認ください。
ご迷惑をおかけして申し訳ありません。#ドカポン https://t.co/STb4A7TncF
今回の記事で紹介したものはコメントの末尾にダメ文字があると想定外コメントアウトがされてしまうという事象でしたが、プログラムの実装によっては途中にダメ文字が入ってもバグることがあるみたいですね。キャラ名に「ソ」をいれるとバグる! 古参開発者「うっ……頭の中で何かが……」/「ドカポンキングダム コネクト」で起きたShift_JIS文字コードの「ダメ文字」問題って?【やじうま… https://t.co/EKcJKTNugw pic.twitter.com/uRCXpWq7af
— 窓の杜 (@madonomori) April 14, 2023
まとめ
たかがコメントアウトと思っていましたが、調べてみると奥が深かったです。
調べた結果、組み込み系の人がコメントアウトで/**/を使ってい理由は下記2つだと思います。
①古い規格の場合、//が使えないのでどんな規格でも対応できる/**/を使用している。
②Shift-JIS特有のダメ文字によるバグを回避することができる。
もし他にも理由があれば教えていただけると幸いです。
0 件のコメント:
コメントを投稿