从未定义结构

时间:2010-07-19 09:06:58

标签: c struct typedef

在C中使用未定义的结构有什么好处吗?

SQLite源代码中的示例:

/* struct sqlite3_stmt is never defined */
typedef struct sqlite3_stmt sqlite3_stmt;

对象被操纵如下:

typedef struct Vdbe Vdbe;
struct Vdbe {
    /* lots of members */
};


int sqlite3_step(sqlite3_stmt *pStmt) {
    Vdbe *v = (Vdbe*) pStmt;
    /* do stuff with v... */
}

那么为什么不使用通常的抽象类型,在foo.c源中私有定义的实际结构和typedef标题中的公共foo.h

2 个答案:

答案 0 :(得分:15)

这样定义是为了隐藏用户的sqlite3_stmt的实现细节,从而避免内部状态被搞乱。请参阅Opaque pointer

(这也迫使用户仅将类型用作指针,因为结构sqlite3_stmt本身的实现不完整。)


编辑:VDBE(虚拟数据库引擎)只是SQLite3 API的“后端”。我认为后端是可变的,因此sqlite3_stmt*不一定是Vdbe*。不在API中公开Vdbe*,因为不应公开后端细节。

答案 1 :(得分:9)

澄清:你问的是为什么SQLite会做上述事情而不是这样做:

标题文件:

typedef struct sqlite3_stmt sqlite3_stmt;

C档案:

struct sqlite3_stmt {
    /* lots of members */
};


int sqlite3_step(sqlite3_stmt *pStmt) {
    /* do stuff with pStmt... */
}

(这是KennyTM答案中链接的“不透明指针”模式的规范形式。)

我能想到SQLite为什么会这样做的唯一理由如下:

我推测,后端代码来自API并使用了名称Vdbe - 这个名称可能意味着与“虚拟数据库条目”的实现相关的东西(在这里疯狂地猜测)

当创建API时,有人意识到sqlite3_step所需的参数是Vdbe,但这并不是一个能够向API的用户传达很多信息的名称。因此,从用户的角度来看,Vdbe被称为sqlite3_stmt

然后,这里的观点是区分同一项目的两个视图:后端根据Vdbe s(无论它们是什么)进行思考,因为这是一个在<上下文中有意义的名称EM>实施。 API讨论sqlite3_stmt,因为这是一个在接口的上下文中有意义的名称。

编辑:正如Amarghosh所指出的,为什么不这样做才能达到同样的效果?

typedef struct Vdbe sqlite3_stmt;

KennyTM points out a good possible reason(请把他投票给我,我不想在这里掏出他的代表):VDBE只是几个可能的后端中的一个;接口使用“泛型”sqlite3_stmt,然后将其转换为后端用于实现它的任何内容。