Как вы определяете непрозрачный массив структур в C?

У меня есть код в моем заголовочном файле, который выглядит так:

typedef struct _bn bnode;

я могу сделать

bnode b;

просто отлично, но

b[i], где i - int, выдает следующую ошибку:

недопустимое использование неопределенного типа ‘struct _bn’

Есть идеи?


person joemoe    schedule 09.10.2009    source источник
comment
У вас не должно быть возможности написать даже один 'bnode b;', потому что компилятор не знает, сколько места нужно выделить. Однако вы могли бы написать «bnode *bp;».   -  person Jonathan Leffler    schedule 10.10.2009


Ответы (5)


Что касается API/библиотеки, обычно, если вам понадобится непрозрачная структура, вы не позволяете пользователю API объявлять такие вещи, как массивы или статические экземпляры из-за этого. Не знать ничего о структуре - это название игры, поэтому вам, вероятно, придется определить некоторые функции для управления ими. Большинство библиотек C, которые объявляют непрозрачные структуры, часто имеют функции доступа и модификации.

Один пример взят из Lua (очевидно, что состояние Lua — это структура одноразового использования, но это идея):

typedef struct lua_State lua_State;
void lua_pushnumber(lua_State *s, lua_Number n);

В этом случае, если вы решили, что вам нужно несколько состояний Lua, вы должны сделать что-то вроде следующего:

lua_State *states[5];
for(int i = 0; i < 5; i++)
    states[i] = lua_open();

Я думаю, что общее эмпирическое правило заключается в том, что если вы работаете с непрозрачными структурами, вы будете работать только с указателями, что в любом случае является практически единственным способом сделать это.

person Nick Bedford    schedule 10.10.2009

Как уже говорилось, b не является массивом и, как таковой, не может быть доступен как единое целое.

Кроме того, как вы ожидаете, что компилятор определит размер этой структуры? Когда вы делаете что-то вроде bnode b[i], определенное количество места должно быть отведено для последующего использования. Как у вас там нет размера.

Что ваша непрозрачность предназначена для вас? Может быть, если вы объясните, чего вы пытаетесь достичь, вы получите более показательный ответ...

person ezpz    schedule 09.10.2009
comment
Да ты прав. Я понял, что sizeof() на самом деле невозможен, и поэтому b[i] не может работать. - person joemoe; 09.10.2009
comment
А, я интерпретировал скобки как перегруженный вызов operator[]. - person tfinniga; 09.10.2009
comment
@joemoe Вы можете использовать что-то вроде void* или подобных механизмов. - person ezpz; 09.10.2009
comment
@tfinniga Да, это было неоднозначно, поэтому я попытался охватить обе ситуации. - person ezpz; 09.10.2009

Похоже, вам либо нужна реализация непрозрачного указателя/PIMPL, либо вы должны включить соответствующий заголовочный файл .

Структуры в C++ почти идентичны классам, поэтому применяются те же методы.

person tfinniga    schedule 09.10.2009
comment
Я предпочитаю не использовать непрозрачный указатель, как описано в этой статье, потому что он может ввести пользователя функции в заблуждение, заставив его думать, что это тип значения. - person joemoe; 09.10.2009

Вы не можете определить массив непрозрачных структур. Если вы это сделаете, вы получите сообщение об ошибке, например:

ошибка: тип массива имеет неполный тип элемента

(конкретный текст ошибки будет отличаться; тот, что выше, взят из gcc 4.4.1).

Но что вы можете сделать, так это создать массив указателей на непрозрачные структуры. Это выполнимо, поскольку детали структуры не влияют на размер указателя.

typedef struct _bn bnode;
bnode *b[20];
person R Samuel Klatchko    schedule 09.10.2009
comment
Это обычный способ работы с непрозрачными структурами. - person caf; 10.10.2009

Вы должны, по крайней мере, знать размер bnode, чтобы иметь возможность сделать из них массив.

Вы могли бы сделать в своем непрозрачном определении bnode:

typedef struct bnode_struct {
   uint8_t opaque_bytes[1024]; /* magically just "know" how big it is. */
} bnode;

Затем вы можете сделать:

bnode b[10];

и это будет работать.

person smcameron    schedule 09.10.2009
comment
Это может сработать. но bnode может не иметь такого же требования к выравниванию, как непрозрачная версия структуры, см. мой вопрос/ответ для получения дополнительной информации об этом: stackoverflow.com/questions/17619015/ - person Yann Droneaud; 12.07.2013