gotoだらけのFizzBuzz
概要
goto不要論の話をちょくちょく耳にするのですが、
実際goto乱用するとどれくらい読みづらくなるのか気になりました。
ということで、至って一般的なFizzBuzzをgotoを乱用して実装してみよう、と考えた次第です。
通常のFizzBuzz
C言語でFizzBuzzを実装すると普通はこんな感じになるかと思います。
僕は普段C言語を書かないので、今回の記事のためだけにC言語の勉強をしました。
(何やってんだ...)
C言語の勉強をしたのは学生のころなので、もはやすべて記憶の彼方です。
#include <stdio.h>
#include <string.h>
int main(void) {
const int MAX = 100;
int i = 1;
char text[256] = "";
while (1) {
if (i % 3 == 0) strcat(text, "Fizz");
if (i % 5 == 0) strcat(text, "Buzz");
if (text[0] == '\0') sprintf(text, "%d", i);
printf("%s\n", text);
text[0] = '\0';
if (MAX <= i) {
break;
}
i++;
}
return 0;
}
よくあるFizzBuzzだと思います。
よしとけばいいのにこれをgotoだけで実装して見ようと思います。
FizzBuzz with goto
gotoしたものがこちらになります。
#include <stdio.h>
#include <string.h>
int main(void) {
const int MAX = 100;
int i = 1;
char text[256];
loop:
goto append_fizz; append_fizz_end:
goto append_buzz; append_buzz_end:
goto set_number; set_number_end:
goto print; print_end:
goto clear_text; clear_text_end:
goto goto_end; goto_end_end:
goto increment_counter; increment_counter_end:
goto loop;
append_fizz:
if (i % 3 == 0) strcat(text, "Fizz");
goto append_fizz_end;
append_buzz:
if (i % 5 == 0) strcat(text, "Buzz");
goto append_buzz_end;
set_number:
if (text[0] == '\0') sprintf(text, "%d", i);
goto set_number_end;
print:
printf("%s\n", text);
goto print_end;
clear_text:
text[0] = '\0';
goto clear_text_end;
goto_end:
if (MAX < i) goto end;
goto goto_end_end;
increment_counter:
i++;
goto increment_counter_end;
end:
return 0;
}
なんだこれは...(困惑)
すべての処理をgotoのブロックにしてしまって、goto -> XXX_end でもとのブロックに戻ってくるという実装にしました。
ループもforのカウンタ変数を使うのではなく、gotoのジャンプ先でカウンタ変数を更新して戻ってきます。
見るからにつらい。
ここまで極端な実装することは無い(と思いたい)ですが、こういうのが乱用されると混乱しそうですね。
まだgotoできる
これで実装終わって満足したんですが、 strcat
関数があることに気づきました。
strcat
関数を呼ぶためだけに string.h
ヘッダをinlcudeしてるんですよね。
これ、gotoにできるな、と気づきました。
ということで、さらにgotoすることにしました。
FizzBuzz with goto 2
さらにgotoしたものがこちらになります。
#include <stdio.h>
#define MAX_SIZE 256
int main(void) {
const int MAX = 100;
int i = 1;
int j = 0;
int k = 0;
char text1[MAX_SIZE];
char text2[MAX_SIZE];
int append_type;
int unused_var;
loop:
goto append_fizz; append_fizz_end:
goto append_buzz; append_buzz_end:
goto set_number; set_number_end:
goto print; print_end:
goto clear_text; clear_text_end:
goto goto_end; goto_end_end:
goto increment_counter; increment_counter_end:
goto loop;
append_fizz:
if (0 == i % 3) {
text2[0] = 'F';
text2[1] = 'i';
text2[2] = 'z';
text2[3] = 'z';
text2[4] = '\0';
append_type = 1;
goto strcat; strcat_append_fizz_end:
unused_var = 1;
}
goto append_fizz_end;
append_buzz:
if (0 == i % 5) {
text2[0] = 'B';
text2[1] = 'u';
text2[2] = 'z';
text2[3] = 'z';
text2[4] = '\0';
append_type = 2;
goto strcat; strcat_append_buzz_end:
unused_var = 1;
}
goto append_buzz_end;
set_number:
if ('\0' == text1[0]) sprintf(text1, "%d", i);
goto set_number_end;
print:
printf("%s\n", text1);
goto print_end;
clear_text:
text1[0] = '\0';
goto clear_text_end;
goto_end:
if (MAX < i) goto end;
goto goto_end_end;
increment_counter:
i++;
goto increment_counter_end;
increment_counter_j:
j++;
goto increment_counter_j_end;
increment_counter_k:
k++;
goto increment_counter_k_end;
strcat:
j = 0;
strcat_loop_j:
if ('\0' == text1[j]) {
k = 0;
strcat_loop_k:
text1[j+k] = text2[k];
goto strcat_break; strcat_break_end:
goto increment_counter_k; increment_counter_k_end:
goto strcat_loop_k;
unused_var = 1;
}
goto increment_counter_j; increment_counter_j_end:
goto strcat_loop_j;
strcat_loop_break:
if (1 == append_type) goto strcat_append_fizz_end;
if (2 == append_type) goto strcat_append_buzz_end;
strcat_break:
if ('\0' == text2[k]) goto strcat_loop_break;
goto strcat_break_end;
end:
return 0;
}
なんだこれは...(困惑)
コードにつらみしか無い。
読むのが辛い。
実装するのも辛かった。
gotoから変数を参照するために、関数先頭で使う変数を全部宣言してgoto先でループカウンタ変数のjとkを更新して回ったり、
条件分岐の最後の文がlabelで終了できないので、コンパイルを通すためだけに unused_var = 1
だけしたりと、もはややけくそ。
一応コンパイルできますし、動きます。
⟩ gcc --version
gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
⟩ gcc goto4.c
⟩ ./a.out | head -n 20
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
ループ変数 i が 1 のときだけ違う文字が格納されちゃってるのですが、
もうこの実装を頑張って直すのが辛くなったので諦めました。
まとめ
- goto乱用、ダメ、絶対
Author And Source
この問題について(gotoだらけのFizzBuzz), 我々は、より多くの情報をここで見つけました https://qiita.com/jiro4989/items/da2c58c5985ebe67fa93著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .