一种使用函数指针实现状态机的方法
结构定义
1 struct state_machine {
2 int state;
3![](http://img1.tuicool.com/umARjq.gif)
4 };
5
6 enum {
7 s1,
8 s2,
9![](http://img1.tuicool.com/umARjq.gif)
10 sn
11
};
假设s1为初始状态,状态变迁为s1->s2->...->sn。
常规实现
假设每次调用state_machine_handle时,输入data是变化的,不同的data会改变状态,伪代码框架如下。
1
void handle_s1( struct state_machine * sm, void *
// do something about state 1 4
if
sm -> state =
} 7
8
void handle_s2( struct state_machine * sm, void *
// do something about state 2 11
if
sm -> state =
} 14
15
void handle_sn_1( struct state_machine * sm, void *
// do something about state n-1 18
if
sm -> state =
} 21
22
void state_machine_handle( struct state_machine * sm, void *
switch (sm -> state)
case
break
29
case
break
33
case
break
} 37
}
![](http://img1.tuicool.com/6RJZza.gif)
data)
2![](http://img0.tuicool.com/Nb6ZJz.gif)
{
3![](http://img0.tuicool.com/BrANne.gif)
![](http://img0.tuicool.com/BrANne.gif)
(is_satisfy_s2(data))
5![](http://img0.tuicool.com/BrANne.gif)
s2;
6![](http://img2.tuicool.com/UNFBFn.gif)
![](http://img1.tuicool.com/6RJZza.gif)
![](http://img1.tuicool.com/6RJZza.gif)
data)
9![](http://img0.tuicool.com/Nb6ZJz.gif)
{
10![](http://img0.tuicool.com/BrANne.gif)
![](http://img0.tuicool.com/BrANne.gif)
(is_satisfy_s3(data))
12![](http://img0.tuicool.com/BrANne.gif)
s3;
13![](http://img2.tuicool.com/UNFBFn.gif)
![](http://img1.tuicool.com/6RJZza.gif)
![](http://img1.tuicool.com/6RJZza.gif)
data)
16![](http://img0.tuicool.com/Nb6ZJz.gif)
{
17![](http://img0.tuicool.com/BrANne.gif)
![](http://img0.tuicool.com/BrANne.gif)
(is_satisfy_sn(data))
19![](http://img0.tuicool.com/BrANne.gif)
sn;
20![](http://img2.tuicool.com/UNFBFn.gif)
![](http://img1.tuicool.com/6RJZza.gif)
![](http://img1.tuicool.com/6RJZza.gif)
data)
23![](http://img0.tuicool.com/Nb6ZJz.gif)
{
24![](http://img0.tuicool.com/ZBBVny.gif)
{
25![](http://img0.tuicool.com/BrANne.gif)
s1:
26![](http://img0.tuicool.com/BrANne.gif)
handle_s1(sm,data);
27![](http://img0.tuicool.com/BrANne.gif)
;
28![](http://img0.tuicool.com/BrANne.gif)
![](http://img0.tuicool.com/BrANne.gif)
s2:
30![](http://img0.tuicool.com/BrANne.gif)
handle_s2(sm,data);
31![](http://img0.tuicool.com/BrANne.gif)
;
32![](http://img0.tuicool.com/BrANne.gif)
![](http://img1.tuicool.com/umARjq.gif)
![](http://img0.tuicool.com/BrANne.gif)
sn:
34![](http://img0.tuicool.com/BrANne.gif)
handle_sn(sm,data);
35![](http://img0.tuicool.com/BrANne.gif)
;
36![](http://img2.tuicool.com/j6fq63.gif)
![](http://img2.tuicool.com/UNFBFn.gif)
sm->state初始化为s1。
改进实现
为了免去丑陋的switch case分支结构,用成员函数指针handler替代了state,改进后的框架如下。
1
struct
typedef void ( * state_handler)( struct state_machine * , void *
4
struct state_machine
state_handler handler ; 6
7
}
9
void handle_s1( struct state_machine * sm, void *
// do something about state 1 12
if
sm -> handler = handle_s2 ; 14
} 15
16
void handle_s2( struct state_machine * sm, void *
// do something about state 2 19
if
sm -> handler = handle_s3;
21
23
void handle_sn_1( struct state_machine * sm, void *
// do something about state n-1 26
if
sm -> handler = handle_sn ;
28
30
void state_machine_handle( struct state_machine * sm, void *
sm -> handler
}
![](http://img1.tuicool.com/6RJZza.gif)
state_machine;
2![](http://img1.tuicool.com/6RJZza.gif)
);
3![](http://img1.tuicool.com/6RJZza.gif)
![](http://img0.tuicool.com/Nb6ZJz.gif)
{
5![](http://img0.tuicool.com/BrANne.gif)
![](http://img0.tuicool.com/BrANne.gif)
![](http://img1.tuicool.com/umARjq.gif)
![](http://img2.tuicool.com/UNFBFn.gif)
;
8![](http://img1.tuicool.com/6RJZza.gif)
![](http://img1.tuicool.com/6RJZza.gif)
data)
10![](http://img0.tuicool.com/Nb6ZJz.gif)
{
11![](http://img0.tuicool.com/BrANne.gif)
![](http://img0.tuicool.com/BrANne.gif)
(is_satisfy_s2(data))
13![](http://img0.tuicool.com/BrANne.gif)
![](http://img2.tuicool.com/UNFBFn.gif)
![](http://img1.tuicool.com/6RJZza.gif)
![](http://img1.tuicool.com/6RJZza.gif)
data)
17![](http://img0.tuicool.com/Nb6ZJz.gif)
{
18![](http://img0.tuicool.com/BrANne.gif)
![](http://img0.tuicool.com/BrANne.gif)
(is_satisfy_s3(data))
20![](http://img0.tuicool.com/BrANne.gif)
}
![](http://img1.tuicool.com/6RJZza.gif)
![](http://img1.tuicool.com/6RJZza.gif)
data)
24![](http://img0.tuicool.com/Nb6ZJz.gif)
{
25![](http://img0.tuicool.com/BrANne.gif)
![](http://img0.tuicool.com/BrANne.gif)
(is_satisfy_sn(data))
27![](http://img0.tuicool.com/BrANne.gif)
}
![](http://img1.tuicool.com/6RJZza.gif)
![](http://img1.tuicool.com/6RJZza.gif)
data)
31![](http://img0.tuicool.com/Nb6ZJz.gif)
{
32![](http://img0.tuicool.com/BrANne.gif)
(sm, data);
33![](http://img2.tuicool.com/UNFBFn.gif)
sm->handler初始化为handle_s1,该方法在性能上应略优于常规方法,而且逻辑更清晰自然,非常适合于网络流的处理,在nginx中分析http和email协议时,得到了广泛应用。