从未定义结构

Axe*_*xel 12 c struct typedef

在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源和公众typedeffoo.h头?

ken*_*ytm 15

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

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


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

  • 不过,在Opaque指针文章的例子中,定义了`struct cat_t` ...`struct sqlite3_stmt`仅用于隐藏`struct Vdbe`上的实现?那么,有没有理由不在'Vdbe`上使用不透明指针模式? (2认同)

Mar*_*n B 9

澄清:你问的是为什么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.

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

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

typedef struct Vdbe sqlite3_stmt;
Run Code Online (Sandbox Code Playgroud)

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

  • 那么为什么不'他们只是'typedef struct Vdbe sqlite3_stmt;` (4认同)