建议用函数指针来实现,可以尽量将不同状态下的逻辑和数据分开,
下面是土鳖的示意代码:
// --------------------------- common.h
/* 表达每一个状态下需要做的事情 */
#define EXTENDS_STATUS \
struct { \
const char* description; \
bool (*prepare_enter)(void* self); \
bool (*prepare_leave)(void* self); \
void (*enter)(void* self); \
void (*leave)(void* self); \
bool (*draw)(void* self); \
bool (*onKey)(void* self); \
}
typedef EXTENDS_STATUS common_status_t;
/* 每一个状态由 (name, common_status_t*) 描述, 比如
("bbsdoc", (common_status_t*)(bbsdoc_status_t*)),
每个 common_status_t 的“子类”实现的源文件里都实现
一个 status_on_load() 函数,这个函数调用 register_new_status(),
主程序就可以用 dlopen, dlsym 将 xxx_status_t 对应的结构体注册
到一个全局数组里头。
*/
bool register_new_status(const char* name,
common_status_t* status);
/* 切换到另一个状态 */
bool goto_status(const char* name)
{
common_status_t* old = g_current_status;
common_status_t* new = find_status(name);
if (old->prepare_leave(old))
old->leave();
else
abort();
if (new->prepare_enter(new))
new->enter();
else
abort();
g_current_status = new;
}
// -------------------------- bbsdoc.c
typedef struct {
EXTENDS_STATUS;
int bid;
....
} bbsdoc_status_t;
static bbsdoc_status_t bbsdoc_status;
void status_on_load() {
// 设置 bbsdoc_status 的成员
register_new_status("bbsdoc", &bbsdoc_status);
}
// ------------------------- main.c
goto_status("mainmenu");
while (NULL != g_current_status) {
g_current_status->onKey(g_current_status);
g_current_status->draw(g_current_status);
}
【 在 pig2532 (猪猪猪) 的大作中提到: 】
: 标 题: 大打倒计划 pig2532
: 发信站: 水木社区 (Tue Jan 6 18:54:17 2009), 站内
:
: 寄信人: pig2532 (猪猪猪)
: 标 题: 大打倒计划
: 发信站: 水木社区 (Mon Jun 16 19:38:18 2008)
: 来 源: 211.151.94.140
:
: 现在显示版面列表、阅读文章、目录版面、新分类讨论区等等显示和跳转很混乱
: 并且记录在版时间也很困难和混乱
: 现在提出大打倒计划
:
: 使用全局结构体记录用户当前的阅读状态,像这个样子
: struct global_status {
: int type; /* 全局阅读状态
: GS_NONE: 不在阅读状态
: GS_ALL: 所有版面列表或者分区版面列表
: GS_NEW: 新分类讨论区
: GS_FAV: 个人定制区
: GS_GROUP: 目录版面
: GS_BOARD: 版面
: GS_MAIL: 信箱 */
: int sec; /* 所在分区
: -1: 超级版面选择
: 0: 所有版面列表
: N: 在第N区 */
: int favid; /* 新分类讨论区或个人定制区的目录号 */
: int bid; /* 目录版面或普通版面的序号 */
: int mode; /* 版面索引模式或信箱索引模式
: DIR_MODE_NORMAL, DIR_MODE_DIGEST.... */
: int filter; /* 是否在超级文章选择 */
: };
:
: 该全局结构体有两个:
: struct global_status gs_curr, gs_new;
: 其中gs_curr记录当前用户状态,gs_new记录即将变化到的新状态。
:
: 整个阅读状态由一个大循环构成:
: int read_loop()
: struct global_status gs_this_level; /* 这个用来记录这一层的状态 */
: while(true) {
: 记录当前时间;
: 根据gs_curr.type运行相应的阅读函数;
: 记录当前时间并写入日志;
: 判断gs_new与gs_curr的区别;
: if(需要递归进去) {
: 将gs_curr保存到gs_this_level;
: 将gs_new赋值到gs_curr;
: read_loop();
: 将gs_this_level恢复到gs_curr;
: }
: else
: 将gs_new赋值到gs_curr;
: if(gs_curr.type == GS_NONE)
: break;
: }
: }
:
: 阅读函数有5个,分别对应于type表示的五种状态。
: 在这五个阅读函数里,有可能出现以下情形的跳转:
: (1) 摁S跑到其它版面或新分类讨论区去了。
: (2) 进入下一级的某个新分类讨论区或个人定制区目录了。
: (3) 退回到上一级的目录了。
: (4) 摁V跑到信箱里去了。
: (5) 摁H跑到十大的别的版面去了。
: (6) 跑到版面文摘区或其它模式了。
: 以上情形均是在5种阅读模式之间跳转,在阅读函数中,无论哪一种跳转都不能直接调用。
: 在阅读函数中凡是需要跳转的,必须且只能修改gs_new并返回。
:
: --
: Hallowed are the Ori
: ※ 修改:·pig2532 于 Jun 16 19:38:38 2008 修改本文·[FROM: 211.151.94.*]
--
修改:pig2532 FROM 211.151.94.*
FROM 211.157.41.*