从未定义结构
在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_step
是Vdbe
,但这并不是一个能够向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*
,因为不应公开后端细节。