在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头?
ken*_*ytm 15
它被定义为隐藏用户的实现细节sqlite3_stmt,从而避免内部状态被混乱.请参见不透明指针.
(这也会强制用户仅将类型用作指针,因为结构sqlite3_stmt本身的实现不完整.)
编辑:VDBE(虚拟数据库引擎)只是SQLite3 API的"后端".我认为后端是可变的,因此sqlite3_stmt*不一定是Vdbe*.不在Vdbe*API中公开,因为不应公开后端细节.
澄清:你问的是为什么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是a Vdbe,但这并不是一个可以向API的用户传达很多信息的名称.因此,从用户的角度来看,a Vdbe被称为sqlite3_stmt.
这里的要点是区分同一项目的两个视图:后端根据Vdbes(无论它们是什么)来思考,因为这是一个在实现的上下文中有意义的名称.API讨论sqlite3_stmts,因为这是一个在界面上下文中有意义的名称.
编辑:正如Amarghosh所指出的,为什么不这样做才能达到同样的效果呢?
typedef struct Vdbe sqlite3_stmt;
KennyTM指出了一个很好的理由(请把他投票给我,我不想在这里掏出他的代表):VDBE只是几个可能的后端之一; 接口使用"泛型" sqlite3_stmt,然后将其转换为后端用于实现它的任何内容.