Подтвердить что ты не робот

Не определенная структура

Есть ли какая-либо польза в том, что в 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?

4b9b3361

Ответ 1

Чтобы уточнить: то, что вы спрашиваете, почему 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, был Vdbe, но это было не совсем имя, которое могло бы передать пользователю API. Следовательно, с точки зрения пользователя a Vdbe называется sqlite3_stmt.

Таким образом, здесь следует различать два представления одного и того же элемента: Бэкэнд думает в терминах Vdbe (независимо от того, что они есть), потому что это имя имеет смысл в контексте реализации. API говорит о sqlite3_stmt, потому что это имя имеет смысл в контексте интерфейса.

Изменить: Как указывает Амархош, почему бы просто не сделать это для достижения того же эффекта?

typedef struct Vdbe sqlite3_stmt;

KennyTM указывает на хорошую возможную причину (пожалуйста, проголосуйте за него, я не хочу отключать его репутацию здесь): VDBE является лишь одним из нескольких возможных бэкэнды; интерфейс использует "общий" sqlite3_stmt, и затем он применяется к тому, что использует бэкэнд для его реализации.

Ответ 2

Он определяется как это, чтобы скрыть деталь реализации sqlite3_stmt от пользователя, что позволяет избежать совпадения внутренних состояний. См. Непрозрачный указатель.

(Это также заставляет пользователя использовать этот тип в качестве указателя, поскольку сама структура sqlite3_stmt имеет неполную реализацию.)


Изменить: VDBE (движок виртуальной базы данных) - это всего лишь "исходный код API SQLite3". Я считаю, что back-end изменчив, поэтому sqlite3_stmt* не обязательно a Vdbe*. Не выставлять Vdbe* в API, потому что фоновая деталь не должна отображаться.