Friday 10 August 2007
Switch 文の実装
Cのswitch文にポインタが使えないとかいう話があったので、うっかり実装を考えると言う羽目に。言うのは簡単なんだよな〜
まず、C でコンパイルしてみる。
int a,b,c,d;
int
main(int ac,char *av[])
{
int *p[] = {&a,&b,&c,&d};
#if 0
switch((int)(p[ac])) {
case (int)&a:
printf("a\n"); break;
case (int)&b:
printf("b\n"); break;
case (int)&c:
printf("c\n"); break;
case (int)&d:
printf("d\n"); break;
default:
printf("unknown\n");
}
#endif
#if 1
switch((p[ac])-&a) {
case &a-&a:
printf("a\n"); break;
case &b-&a:
printf("b\n"); break;
case &c-&a:
printf("c\n"); break;
case &d-&a:
printf("d\n"); break;
default:
printf("unknown\n");
}
#else
if (p[ac]==&a) {
printf("a\n");
} else if (p[ac]==&b) {
printf("b\n");
} else if (p[ac]==&c) {
printf("c\n");
} else if (p[ac]==&d) {
printf("d\n");
} else {
printf("unknown\n");
}
#endif
確かに動かない。
xxxx.c:27: error: case label does not reduce to an integer constant
if 文なら動く。switch 文はtable参照にコンパイルするための構文なので、そのtableを作るためにはコンパイル時に定数である必要がある。アドレスは定数じゃないので、どうしても実行時に解決しないとだめ。
実行時に解決されるってことは、table にしても、結局、hashかなんかで引く必要があるってことだよ。sort も出来ないので、binary search も出来ないし。
結局、考え付くのは、switch 文があったら、if/else if に書き換えてコンパイルするって手法だな。ポインタをswitch文に使える言語では、おそらくそうなっていると思った方が良い。switch 文だから速いとは限らないって奴だね。
hash or sort でtableを実行時に再構成するなら、 まぁ、やってやれないことはないんだが、いつ誰がやるかっていう問題があるので、 それはコンパイラではなく自分でやるべきだと思う。
そもそも、ポインタ持ってるんだったら、state pattern 使って、
void exec_a() { printf("a\n"); }
void exec_b() { printf("b\n"); }
void exec_c() { printf("c\n"); }
void exec_d() { printf("d\n"); }
struct sw {
void (*exec)();
} a = { .exec = exec_a} ,b = { .exec = exec_b} ,
c = { .exec = exec_c} ,d = { .exec = exec_d} ;
int
main(int ac,char *av[])
{
struct sw *p[] = {&a,&b,&c,&d};
p[ac]->exec();
return 0;
}
とかしろよ。これだから、××な奴は... と思ったのだった。結局、言語仕様が複雑になるだけじゃん。Perl がswitch文を持たない理由の一つなんだろうな〜
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment