関数ジャンプテーブルサンプル

Cでよく使われる(?)関数ポインタを用いたステートマシンのサンプルです。

Cでよく使われる(?)関数ポインタを用いたステートマシンのサンプルです。

  • タグ:
  • c
#include <stdio.h>

// 状態番号
static unsigned char sucState;
// 投入金額
static int siCharge;
// Suica残高(仮)
static int siSuica = 2000;

// 状態
enum E_STATE{
	IDLE = 0,
	POOR,
	SELECTED,
	SUFFICE,
	STATE_MAX
};
// イベント
enum E_EVENT{
	INJECT = 0,
	CHANGE,
	SUICA,
	JUICE_SELECT,
	EVENT_MAX
};

// ジュースの値段
const int JUICE_PRICE = 120;
// 
const char MESSAGE[EVENT_MAX][20]= {
	"100円投入",
	"おつり返却",
	"Suicaタッチ",
	"ジュース選択"
};

// 関数ポインタの型宣言
typedef int (*JumpTable)( int* );

// ダミー関数宣言
int Dummy( int * );

// 関数宣言
int St00Ev00( int* );
int St00Ev02( int* );
int St00Ev03( int* );
int St01Ev00( int* );
int St01Ev01( int* );
int St02Ev02( int* );
int St03Ev00( int* );
int St03Ev03( int* );

// ジャンプテーブルの登録
const JumpTable fpVendingMachine[STATE_MAX][EVENT_MAX] = {
	//	100円投入	おつり返却	Suicaタッチ	ジュース選択
	{	&St00Ev00,	&Dummy,		&St00Ev02,	&St00Ev03	},	// 初期状態
	{	&St01Ev00,	&St01Ev01,	&Dummy,		&Dummy		},	// 金額不足状態
	{	&Dummy,		&Dummy,		&St02Ev02,	&Dummy		},	// ジュース選択状態
	{	&St03Ev00,	&St01Ev01,	&Dummy,		&St03Ev03	},	// 購入可能状態
};

// ダミー関数
int Dummy( int *arg ) {
	return( sucState );
}

int St00Ev00( int *arg ) {
	*arg += 100;
	return( POOR );
}
int St00Ev02( int *arg ) {
	printf("Suica残高:%d円\n",*arg);
	return( sucState );
}
int St00Ev03( int *arg ) {
	printf("ジュース選択\n");
	return( SELECTED );
}
int St01Ev00( int *arg ) {
	int ret = sucState;
	St00Ev00( arg );
	if ( siCharge >= JUICE_PRICE ) {
		ret = SUFFICE;
	}
	return( ret );
}
int St01Ev01( int *arg ) {
	printf("%d円返却\n",*arg);
	*arg = 0;
	return( IDLE );
}
int St02Ev02( int *arg ) {
	int ret = IDLE;
	if ( *arg >= JUICE_PRICE ) {
		ret = St03Ev03( arg );
	}
	return( ret );
}
int St03Ev00( int *arg ) {
	*arg += 100;
	return( sucState );
}
int St03Ev03( int *arg ) {
	int ret = IDLE;
	printf("ジュース購入!\n");
	*arg -= JUICE_PRICE;
	if ( fpVendingMachine[sucState][CHANGE] != Dummy ) {
		if ( *arg < JUICE_PRICE ) {
			ret = fpVendingMachine[sucState][CHANGE](arg);
		} else {
			ret = sucState;
		}
	}
	return( ret );
}


int main( int argc, char* argv[] )
{
	int i, c, event, *p;

	// メインループ
	while( 1 ){
		// コマンド表示
		for( i = 0; i < EVENT_MAX; i++ ){
			if ( fpVendingMachine[sucState][i] != Dummy ) {
				printf("%d:%s\n", i,MESSAGE[i] );
			}
		}
		puts("");

		// コマンド入力
		scanf("%d",&c);
		fflush( stdin );
		event = ( c >= 0 && c <= EVENT_MAX )? c: EVENT_MAX;
		if ( event >= EVENT_MAX ) {
			puts("error");
			continue;
		}
		if ( event == SUICA ) {
			p = &siSuica;
		} else {
			p = &siCharge;
		}

		// 関数コール
		sucState = fpVendingMachine[sucState][event](p);
	}
	return( 0 );
}