从未定义结构

在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源中私有定义的实际结构和foo.h头中的公共typedef

澄清一下:你问的是为什么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答案中链接的“不透明指针”模式的规范forms。)

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

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

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

这里的要点是区分同一项的两个视图:后端根据Vdbe (无论它们是什么)来思考,因为这是一个在实现的上下文中有意义的名称。 API讨论了sqlite3_stmt因为这是一个在接口上下文中有意义的名称。

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

 typedef struct Vdbe sqlite3_stmt; 

KennyTM指出了一个很好的理由 (请把他投票给我,我不想在这里掏出他的代表):VDBE只是几个可能的后端之一; 接口使用“通用” sqlite3_stmt ,然后将其转换为后端用于实现它的任何内容。

它被定义为从用户隐藏sqlite3_stmt的实现细节,从而避免内部状态被搞乱。 请参见不透明指针

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


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