コメント行があるとなぜか動くコードがあるらしい
コメント行があるとなぜか動くコード
以下のようなコメントを見たことはないでしょうか?
// 理由はわからないが動く
...
// よくわからないがこれがないとダメらしい
...
// ↓↓↓↓このコメントを消すと動かなくなる!絶対消すな!↓↓↓↓
...
私はエンジニア歴がそれほど長いわけではありませんが、何度か目にしたことがあります[1]。
よくこれでレビュー通ったなと思いつつ、正直もうプロダクションコードに組み込まれているんだし、まあいっかと済ませてしまっています[2]。
それはさておき、知人から次のようなコードを教えてもらいました。
これは「この行のコメントを消すとなぜか動かない」コードです。
#include <stdio.h>
int main(void) {
int i = 10;
// iの値により分岐可能
// この行のコメントを消すとなぜか動かない
if (i > 5) {
printf("OK\n");
} else {
printf("NG\n");
}
return 0;
}
調べていると「文字コードの5C問題」としてちらほら出てくるので、それなりに有名なのでしょうか?
せっかくなので調べた内容をまとめたいと思います。
原因
これはコードをShift-JISで保存し、それをLinux gccでコンパイルすると発生します。
つまりというか案の定というか、文字コードが原因なのですね。
Shift-JISでは能
の文字コードが945c
であり、この5c
が\
扱いとなります。
実際にPython (v3.11.0) で確認していると、たしかに文字コードは945c
です[3]。
print("能".encode("utf-8").hex()) # e883bd
print("能".encode("shift_jis").hex()) # 945c
そしてこの\
はコンパイラによって扱いが異なりますが、少なくともLinux gccでは
- 次の行もコメントとして扱う
という処理になります。
その結果、if (i > 5) {
の部分がコメント扱いとなってコンパイルエラーとなるわけですね。
実際にやってみる
ここで終わってもよいのですが、せっかくなので実際にコンパイルエラーを出してみます。
まずは以下のように適当なDockerプロジェクトを作成します。
shiftjis.c
, utf8.c
は上述のコードをそれぞれShift-JISとUTF-8で保存したファイルです。
$ tree . -a
.
├── Dockerfile
└── src
├── shiftjis.c
└── utf8.c
Dockerfileは以下です。Dockerは凝りだすと切りがないので、とにかくgccコマンドが動く環境を作ります。
FROM gcc:latest
WORKDIR /workdir
これをビルドして実行してみます。コメントアウトがそのままだと問題なく動きました。
$ docker image build -t gcc_compiler .
$ docker container run -v $(pwd)/src:/workdir gcc_compiler bash -c \
"gcc -o output shiftjis.c && ./output"
OK
そしてコメントを削除してから再度実行すると、無事(?)エラーが出てきました。
もちろんUTF-8では問題なく動きます。
$ docker container run -v $(pwd)/src:/workdir gcc_compiler bash -c \
"gcc -o output shiftjis.c && ./output"
shiftjis.c: In function 'main':
shiftjis.c:12:9: error: 'else' without a previous 'if'
12 | else
| ^~~~
この問題はShift-JISで末尾が5c
となる文字がコメント末尾に来ると発生します。
たとえば暴
、噂
、構
などがあります。次のようなコードでも同じエラーが出ます。
int main(void)
{
int i = 10;
// スマートに動くコードだと業界で噂
if (i > 5)
{ ... }
}
#include <stdio.h>
int main(void)
{
int i = 10;
// 嫌な予感がしているんです。そろそろなにかありそうですよ風暴
if (i > 5)
{ ... }
}
まとめ
-
945c
(能
) など、Shift-JISで\
に該当する5c
が末尾に来るコードを実行すると意図しない動作になることがある - 類似の文字コードを調べても、同僚によっぽどの変人がいない限り「可能」以外では起こらない問題のはず
- UTF-8を使いましょう
補足と反省:ChatGPTに聞いてみる
この記事を書く際に上述の内容が正しいかChatGPTに質問すると、次のように反論されました。
ちなみにChatGPT4を使っています。
Shift-JIS では、「能」の文字コードは
92AB
です。945c
はShift-JISでの「能」の文字コードではありません。
英語の方がいいのかな?と思い
What is the character code for
能
in Shift-JIS?
と聞いてみても
The character "能" (which means "ability" or "can" in English) has the Shift-JIS code
0x939F
. You can convert it to hexadecimal representation to verify in various programming languages or tools that can handle Shift-JIS encoding.
となってしまいます。
文字コードの分野では怪しい回答になりますね。日本語特有の話だからでしょうか?
WebPilotを使って調べさせてみます。
ネット上の情報を根拠としてShift-JISにおける「能」の文字コードを調べてください。
すると次の回答がありました。今度は問題なさそうですが、コードを実行して真偽を確認できない分野は怖いですね。
本題とはズレてしまいますが反省として記しておこうと思います。
Shift-JIS(シフトJIS)は、日本語の文字を表現するための文字コードの一つです。文字「能」のShift-JISコードを調べるために、ウェブ上の情報を参照しましょう。以下の手順で進めます:
- WebPilotツールを使用して、ウェブ上で「Shift-JIS "能" 文字コード」に関する情報を検索します。
- 検索結果から関連する情報を抽出します。
(省略)
「能」の文字に関するShift-JISコードは「945C」となります。この情報は、ウェブページから取得されました。
Discussion