在C中使用未定义的结构有什么好处吗?
SQLite源代码中的示例:
/* struct sqlite3_stmt is never defined */
typedef struct sqlite3_stmt sqlite3_stmt;
Run Code Online (Sandbox Code Playgroud)
对象被操纵如下:
typedef struct Vdbe Vdbe;
struct Vdbe {
/* lots of members */
};
int sqlite3_step(sqlite3_stmt *pStmt) {
Vdbe *v = (Vdbe*) pStmt;
/* do stuff with v... */
}
Run Code Online (Sandbox Code Playgroud)
那么,为什么不直接使用通常的抽象类型,在私下定义的实际结构foo.c
源和公众typedef
的foo.h
头?
ken*_*ytm 15
它被定义为隐藏用户的实现细节sqlite3_stmt
,从而避免内部状态被混乱.请参见不透明指针.
(这也会强制用户仅将类型用作指针,因为结构sqlite3_stmt
本身的实现不完整.)
编辑:VDBE(虚拟数据库引擎)只是SQLite3 API的"后端".我认为后端是可变的,因此sqlite3_stmt*
不一定是Vdbe*
.不在Vdbe*
API中公开,因为不应公开后端细节.
澄清:你问的是为什么SQLite做了以上而不是这样做:
头文件:
typedef struct sqlite3_stmt sqlite3_stmt;
Run Code Online (Sandbox Code Playgroud)
C档案:
struct sqlite3_stmt {
/* lots of members */
};
int sqlite3_step(sqlite3_stmt *pStmt) {
/* do stuff with pStmt... */
}
Run Code Online (Sandbox Code Playgroud)
(这是KennyTM答案中链接的"不透明指针"模式的规范形式.)
我能想到SQLite为什么会这么做的唯一理由如下:
我推测,后端代码来自API并使用了名称Vdbe
- 名称可能意味着与"虚拟数据库条目"(在此疯狂猜测)的实现相关的内容.
当创建API时,有人意识到所需的参数sqlite3_step
是a Vdbe
,但这并不是一个可以向API的用户传达很多信息的名称.因此,从用户的角度来看,a Vdbe
被称为sqlite3_stmt
.
这里的要点是区分同一项目的两个视图:后端根据Vdbe
s(无论它们是什么)来思考,因为这是一个在实现的上下文中有意义的名称.API讨论sqlite3_stmt
s,因为这是一个在界面上下文中有意义的名称.
编辑:正如Amarghosh所指出的,为什么不这样做才能达到同样的效果呢?
typedef struct Vdbe sqlite3_stmt;
Run Code Online (Sandbox Code Playgroud)
KennyTM指出了一个很好的理由(请把他投票给我,我不想在这里掏出他的代表):VDBE只是几个可能的后端之一; 接口使用"泛型" sqlite3_stmt
,然后将其转换为后端用于实现它的任何内容.