C言語におけるswitch文の扱いは要注意である。これを想定して書いたつもりが、実際にはありえないことになってしまうこともあるからである。
落とし穴の実例
以下のコードがあったとする。
#include <stdio.h>
#include <stdlib.h>
int main(const int argc, const char *argv[])
{
if (argc != 0) {
return EXIT_FAILURE;
}
int num = atoi(argv[1]);
switch (num) {
case 0:
puts("0");
case 1:
puts("1");
case 2:
puts("2");
default:
puts("default");
}
return EXIT_SUCCESS;
}
上記のコードをswitch.cとして保存し、switch ((Windowsではswitch.exe)) としてコンパイルを行った後、以下のコマンドを入れたら何が出力されるだろうか?
./switch 1
答え
1
2
default
解説
C言語においては、switch文は、あるケースを満たした場合の部分から処理を開始する性質があるが、困ったことに、breakを明示的に入れないと、その次のcaseの処理も行なってしまうという問題をはらんでいる。
例えば、上記のコマンドを入れた場合は、case 1
を満たしているので、その処理を開始した後、そこからブロックを抜けることがなく、case 2
やdefault
の処理まで行ってしまうのである。
これは、見落としてしまって問題となるので、要注意である。
対処法
この場合、基本的には以下の例外を除いてはあるcaseの最後の部分には必ずbreak
を入れるようにすることで対処が可能である。こうすれば、次のcaseに進むことはない。例えば、以下のようにする。
#include <stdio.h>
#include <stdlib.h>
int main(const int argc, const char *argv[])
{
if (argc != 0) {
return EXIT_FAILURE;
}
int num = atoi(argv[1]);
switch (num) {
case 0:
puts("0");
break;
case 1:
puts("1");
break;
case 2:
puts("2");
break;
default:
puts("default");
break;
}
return EXIT_SUCCESS;
}
上記のようにすれば、基本的には問題ない。
例外
例外として、あるcase文の後にその下のケースの処理を行いたい場合は、break
を加えなければいいだけなのだが、その場合、問題を起こすことがあるため、明示的にコメントを入れたほうが良い。例えば、case 1
の場合はcase 2
の処理も行いたいという場合は、以下のようにする。
#include <stdio.h>
#include <stdlib.h>
int main(const int argc, const char *argv[])
{
if (argc != 0) {
return EXIT_FAILURE;
}
int num = atoi(argv[1]);
switch (num) {
case 0:
puts("0");
break;
case 1:
puts("1");
// FALLTHROUGH
case 2:
puts("2");
break;
default:
puts("default");
break;
}
return EXIT_SUCCESS;
}
上記の場合は、case 1
の最後の部分に意図的にFALLTHROUGHというコメントを入れることで、明示的にフォールスルーを行っていることを示すことができる。コード自体は特に意味をなしていないのだが、意図的にフォールスルーを行っているということを判断する重要な材料になる。
最後に
C言語のSwitch文は気づかないうちに問題を起こすことがあるので、しっかりと気をつけたほうが良いだろう。自由度は高いものの、こういうミスでバグが発生するということは念頭に入れたいものである。
ウェブマスター。本ブログでITを中心にいろいろな情報や意見などを提供しています。主にスマートフォン向けアプリやウェブアプリの開発を携わっています。ご用の方はコメントかコンタクトフォームにて。