はじめに
前任者から引き継いだクソコードに絶望的な気分になるのは日常のありふれた風景と言えますね。
クソコードを見てみよう
#include <stdio.h>
int main(void)
{
int i; /* ループ変数 */
const char* f; /* 3 の倍数だったら出力する文字列を格納するポインタ */
const char* b; /* 5 の倍数だったら出力する文字列を格納するポインタ */
/* 1 から 100 の範囲でループする */
for (i = 1; i <= 100; i++)
{
f = ""; /* f を予め空文字列で初期化し */
if (i % 3 == 0) /* i が 3 で割り切れたら */
f = "Fizz"; /* f に "Fizz" の先頭アドレスを代入する ∗/
/* このコメントを消すと動かなくなるので消しちゃダメ! */
b = ""; /* b を予め空文字列で初期化し */
if (i % 5 == 0) /* i が 5 で割り切れたら */
b = "Buzz"; /* b に "Buzz" の先頭アドレスを代入する */
/* f と b が指してる文字列または i の値に改行をつけて出力する */
printf("%s%s%.0d\n", f, b, !*f * !*b * i);
}
/* 0 で終了 */
return 0;
}
例えばこんなコードです。なんだかFizzBuzz問題のようです。なんでこんなコードを引き継ぐのかわけがわかりませんがそういうものと思ってください。
コメントも書かれていて一見まともな様に見えます。ひとつだけ引っかかるのがコードの真ん中辺りに書かれてる
/* このコメントを消すと動かなくなるので消しちゃダメ! */
呪いの言葉です。
とりあえず実行してみよう
C のコードのようなのでとりあえず gcc でコンパイルして実行してみましょう。Wandbox の gcc 13.2.0 を使用してコンパイル、実行してみました。
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
:
~ 略 ~
:
Fizz
97
98
Fizz
Buzz
3 の倍数で"Fizz"、5 の倍数で"Buzz"、3 と 5 の倍数で"FizzBuzz"、それ以外では数字が出力されており良い感じです。
なんだか全然期待外れですね。呪いの言葉もコケ脅しに思えます。せっかくなので先のコメントの行を削除してコンパイル、実行してみましょう。
��1�I��^H��H���PTI��p@
��1�I��^H��H���PTI��p@
Fizz��1�I��^H��H���PTI��p@
��1�I��^H��H���PTI��p@
Buzz
FizzBuzz
Buzz
Buzz
FizzBuzz
Buzz
Buzz
FizzBuzz
Buzz
Buzz
FizzBuzz
:
~ 略 ~
:
FizzBuzz
Buzz
Buzz
FizzBuzz
Buzz
呪いは本当だった!
どうしてこうなった
アッサリ種明かしをすると、
f = "Fizz"; /* f に "Fizz" の先頭アドレスを代入する ∗/
/* このコメントを消すと動かなくなるので消しちゃダメ! */
b = ""; /* b を予め空文字列で初期化し */
/* f に "Fizz" の先頭アドレスを代入する ∗/
のコメントが閉じていません。一見閉じてる様見えますがアスタリスクの文字に U+002A ではなく U+2217 が使用されており複数行コメントを閉じる */
ではないためコメントが閉じられておりません。そのため続く /* このコメントを消すと動かなくなるので消しちゃダメ! */
も含めてひとつのコメントとなっております。
※ 青く選択された部分がひとつのコメント
/* このコメントを消すと動かなくなるので消しちゃダメ! */
の行を削除すると
f = "Fizz"; /* f に "Fizz" の先頭アドレスを代入する ∗/
b = ""; /* b を予め空文字列で初期化し */
b = ""; /* b を予め空文字列で初期化し */
までがひとつのコメントとなり、必要な処理であった b = "";
がコメントアウトされた格好となるので動作に支障を来すようなっております。
アスタリスクに似た文字を紛れ込ますのは前任者の悪意しか感じませんがそう極端な場合でなくとも編集ミスでコード中の */
をウッカリ削除してしまうなんてのはあり得る話で知らない間にコメントが繋がり動作しなくなることは現実にありそうです。
この手の罠は今どきのコンパイラであれば警告オプションを指定すれば
kusocode.c: In function 'main':
kusocode.c:16:9: warning: "/*" within comment [-Wcomment]
16 | /* このコメントを消すと動かなくなるので消しちゃダメ! */
|
容易に発見できたりもするので警告オプションは常に指定するよう習慣づけると良いですね。
おわりに
おわりです。