Есть ли какое-либо преимущество в том, что никогда определило структуры в 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
заголовок?
Чтобы уточнить: вы спрашиваете, почему SQLite выполняет вышеупомянутое вместо этого:
Заголовочный файл:
typedef struct sqlite3_stmt sqlite3_stmt;
Файл C:
struct sqlite3_stmt {
/* lots of members */
};
int sqlite3_step(sqlite3_stmt *pStmt) {
/* do stuff with pStmt... */
}
(Это каноническая форма шаблона «непрозрачный указатель», на который ссылается ответ Кенни.)
Единственная веская причина, по которой я могу думать о том, почему SQLite делает то, что он делает, заключается в следующем:
Я предполагаю, что внутренний код появился до API и использовал имя Vdbe
- имя, вероятно, означает что-то, связанное с реализацией, например, «запись виртуальной базы данных» (здесь дико угадывается).
Когда пришло время создавать API, кто-то понял, что параметр, требуемый для sqlite3_step
, был Vdbe
, но это не совсем то имя, которое многое может передать пользователю. API. Следовательно, с точки зрения пользователя, Vdbe
упоминается как sqlite3_stmt
.
Таким образом, суть здесь состоит в том, чтобы различать два представления одного и того же элемента: серверная часть мыслит в терминах Vdbe
s (какими бы они ни были), потому что это имя имеет смысл в контексте реализация .В API говорится о sqlite3_stmt
s, потому что это имя имеет смысл в контексте интерфейса .
Править: Как указывает Амаргош, почему бы просто не сделать это для достижения того же эффекта?
typedef struct Vdbe sqlite3_stmt;
Кенни TM указывает на серьезную возможную причину (пожалуйста, проголосуйте за него, я не хочу откачивать его репутацию здесь): VDBE - только один из нескольких возможных бэкэндов; интерфейс использует «общий» sqlite3_stmt
, который затем приводится к тому, что серверная часть использует для его реализации.
Это определено таким образом, чтобы скрыть детали реализации sqlite3_stmt
от пользователя, тем самым избегая путаницы во внутренних состояниях. См. Непрозрачный указатель .
(Это также вынуждает пользователя использовать только тип в качестве указателя, поскольку сама структура sqlite3_stmt
имеет неполную реализацию.)
Изменить: VDBE (виртуальный движок базы данных) просто "назад" -оконец API SQLite3. Я считаю, что серверная часть изменяема, поэтому sqlite3_stmt *
не обязательно является Vdbe *
. Не раскрывать Vdbe *
в API, потому что внутренние детали не должны отображаться.