バグ検出ドリル(17)「よくある単純なバグ」だからこそ見つけにくい:山浦恒央の“くみこみ”な話(117)(2/3 ページ)
バグは至るところに、しかも堂々と潜んでおり、自信満々なプログラマーほど、目の前のバグに気付かないものです。「バグ検出ドリル」の第17回の問題は、前回と同じ音楽プレーヤーのプログラムから出題します。「よくある単純なバグ」が潜んでいますが、見つけ出せますか?
4.今回の問題
本プログラムは、音楽プレーヤーのモード遷移を模擬するソフトウェアである。以下に、仕様を示す。プログラムを(リスト1-1、1-2)に、実行結果をリスト2に示す。
リスト2に示す通り、本来は、再生モードで再生指令を出すと、一時停止モードとなるはずだが、再生モードのままとなっている。なぜ遷移しないか、推察せよ。
音楽プレーヤーシミュレーターの仕様
1.概要
本プログラムは、ユーザーのコンソール入力に従って、音楽プレーヤーのモードを表示するものである。
2.詳細
2.1 モードの定義
各モードの定義を以下の表1に示す。
モード | 名称 | |
---|---|---|
MODE_POWER_OFF | 電源OFFモード | |
MODE_IDLE | アイドルモード | |
MODE_PLAY | 再生モード | |
MODE_PAUSE | 一時停止モード | |
表1 モード定義表 |
2.2 モード遷移指令
モード遷移指令の定義とキーボード入力値を以下の表2に示す。
モード(変数名) | 名称 | キーボード入力値 | |
---|---|---|---|
ACT_POWER_ONOFF | 電源ON/OFF指令 | 0 | |
ACT_PLAY | 再生指令 | 1 | |
ACT_STOP | 停止指令 | 2 | |
表2 モード遷移指令表 |
3.モード入力
ユーザーは、コンソールから変更したいモードを入力する。なお、入力値は、表2の通り。
4.モード遷移
4.1 初期モード
プログラム実行時は、電源OFFモードから始まる。
4.2 電源OFFモード
電源OFFモードでのモード遷移を以下に示す。
- ①電源ON指令を入力すると、アイドルモードに遷移する
4.3 アイドルモード
アイドルモードでのモード遷移を以下に示す。
- ①電源OFF指令を入力した場合は、電源OFFモードに遷移する
- ②停止指令を入力した場合は、アイドルモードのままで、遷移しない
- ③再生指令を入力した場合は、再生モードへ遷移する
4.4 再生モード
再生モードでのモード遷移を以下に示す。
- ①電源OFF指令を入力した場合は、電源OFFモードへ遷移する
- ②停止指令を入力した場合は、アイドルモードへ遷移する
- ③再生指令を入力した場合は、一時停止モードへ遷移する
4.5 一時停止モード
一時停止モードでのモード遷移を以下に示す。
- ①電源OFF指令を入力した場合は、電源OFFモードへ遷移する
- ②停止指令を入力した場合は、アイドルモードへ遷移する
- ③再生指令を入力した場合は、再生モードへ遷移する
5.表示機能
コンソールからの入力後、モードに従って以下の文字列をコンソールへ表示する。
- ①電源OFFモード:「電源OFFモード:」
- ②アイドルモード:「アイドルモード:」
- ③一時停止モード:「一時停止モード:」
- ④再生モード:「再生モード:」
6.プログラムの終了
プログラムは、コンソールから「Ctrl+c」を入力すると終了すること。
7.制限事項
入力ミスなどのバグは考慮せず、リスト2の結果が正しくなることを目的とする。なお、環境は、GCC7.3.0を想定する。
/* 音楽プレーヤーシミュレーターヘッダ MusicSim.h */ //モード定義 typedef enum{ MODE_POWER_OFF, //電源OFF MODE_IDLE, //アイドル MODE_PLAY, //再生 MODE_PAUSE //一時停止 }MODE; //モード遷移指令 typedef enum{ ACT_POWER_ONOFF, //電源ON/OFF指令 ACT_PLAY, //再生指令 ACT_STOP //停止指令 }ACT; void output(); //モード出力関数 int gMode; //モード変数(グローバル)
/* 音楽プレーヤーシミュレーター MusicSim.c */ #include <stdio.h> #include "MusicSim.h" int main() { int in; //指令入力用変数 // 初期モードは電源OFFモード gMode = MODE_POWER_OFF; // 初期モードを表示 output(); while(1) { // 指令をコンソールから入力 scanf("%d",&in); switch(gMode){ // 電源OFFモードの場合 case MODE_POWER_OFF: if (in == ACT_POWER_ONOFF) gMode = MODE_IDLE; break; // 再生モードの場合 case MODE_PLAY: if (in == ACT_STOP){ gMode = MODE_IDLE; } else if (in == ACT_PLAY){ gMode = MODE_PAUSE; } else if (in == ACT_POWER_ONOFF){ gMode = MODE_POWER_OFF; } // アイドルモードの場合 case MODE_IDLE: if (in == ACT_PLAY){ gMode = MODE_PLAY; } else if (in == ACT_POWER_ONOFF){ gMode = MODE_POWER_OFF; } break; // 一時停止モードの場合 case MODE_PAUSE: if (in == ACT_STOP){ gMode = MODE_IDLE; } else if (in == ACT_PLAY){ gMode = MODE_PLAY; } else if (in == ACT_POWER_ONOFF){ gMode = MODE_POWER_OFF; } break; default: break; } // モードを表示 output(); } return 0; } // コンソールにモードを表示する void output(){ if (gMode == MODE_POWER_OFF){ printf("電源OFFモード: "); } else if (gMode == MODE_IDLE){ printf("アイドルモード: "); } else if (gMode == MODE_PAUSE){ printf("一時停止モード: "); } else if (gMode == MODE_PLAY) { printf("再生モード: "); } }
リスト2は、下記の手順で実行した結果を示す(先頭の数字は、説明用に追加したもの)。
- ①電源OFFモードで、「0(電源ON/OFF指令)」を入力、Enterを押し、アイドルモードに遷移する
- ②アイドルモードで、「1(再生指令)」を入力、Enterを押し、再生モードに遷移する
- ③再生モードで、「2(停止指令)」を入力、Enterを押し、アイドルモードに遷移する
- ④アイドルモードで、「1(再生指令)」を入力、Enterを押し、再生モードに遷移する
- ⑤再生モードで、「1(再生指令)」を入力、Enterを押し、一時停止モードに遷移するはずが、再生モードのままとなっている
- ⑥コンソールから入力をせず、Ctrl+cでプログラムを終了する
① 電源OFFモード : 0 ② アイドルモード : 1 ③ 再生モード : 2 ④ アイドルモード : 1 ⑤ 再生モード : 1 ⑥ 再生モード :
Copyright © ITmedia, Inc. All Rights Reserved.