структуры типа foward - PullRequest
       33

структуры типа foward

4 голосов
/ 16 ноября 2010
gcc 4.4.4 c89

У меня есть это в моем заголовочном файле.

port.h

struct struct_tag;

int initialize_ports(struct_tag *port);

В моем файле реализации у меня есть это:

port.c

typedef struct struct_tag {
    int port_id;
} Port_t;

И в моем файле driver.h у меня есть следующее:

#include "port.h"
int initialize_ports(struct_tag *port)
{
    port = malloc(sizeof *port);
    /* do checking here */
}

Я заранее объявил структуру, так как хочу скрыть внутренние элементы.

Тем не менее, я получаю следующую ошибку в моих initialize_ports в заголовочном файле:

expected ‘)’ before ‘*’ token

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

Большое спасибо за любой совет,

Ответы [ 4 ]

7 голосов
/ 16 ноября 2010

Вы должны использовать:

int initialize_ports(struct struct_tag *port);
                     ^^^^^^

Кроме того, предварительные объявления дают вам неполный тип , размер которого вы не знаете. Если вам нужно выделить struct struct_tag, вам нужно включить его полное определение. В качестве альтернативы вы можете использовать некоторую функцию create_struct_tag(), если хотите сделать ее полностью непрозрачной.

5 голосов
/ 16 ноября 2010

Как уже отмечалось в других ответах, вы могли бы изменить struct_tag на struct struct_tag в прототипе.Другой способ заставить ваш код компилироваться - написать

typedef struct struct_tag struct_tag;

вместо существующего struct struct_tag; (т.е. объединить typedef с прямым определением).Это тогда позволяет вам писать

int initialize_ports(struct_tag *port)

без ошибок компиляции.Однако это все еще не совсем то, что вы хотите, потому что вызывающая сторона не может ни выделить локальную переменную этого типа, ни malloc () - потому что они не знают размер.

Другие ответы предполагают, чтоВы должны открыть определение структуры.Как правило, это неправильный ответ - потому что он удаляет слой абстракции, который вы пытаетесь создать.Гораздо лучше иметь функции (в port.c, то есть в библиотеке, которую знает о внутренних элементах), например:

struct_tag *create_port(...);
void free_port(struct_tag *port)

, т. Е. Для создания и освобождения структур - и действительнодля других операций (например, чтение из / запись в структуру).

1 голос
/ 16 ноября 2010

Оператор sizeof вычисляется в время компиляции не во время выполнения, поэтому в строке:

port = malloc(sizeof *port);

у компилятора нет информации относительно размера структуры.

Решения включают в себя:

  • полностью определить тип в заголовочном файле.
  • определить initialize_ports() в port.c после структура полностью определена.
  • имеет initialize_ports() вызов функции, определенной в ports.c, чтобы получить размер Port_t во время выполнения.

В любом случае вам следует , а не определять initialize_ports() в файле заголовка driver.h, если ваш компилятор не поддерживает ключевое слово inline или _inline и , которые вы используете. Однако такое использование сделало бы код не совместимым с ISO C и, следовательно, менее переносимым, однако из-за стандартной поддержки C ++ для ключевого слова вы, вероятно, найдете его как расширение в большинстве цепочек инструментов C, которые включают в себя компиляцию C ++, если Вы не используете чрезмерно строгие параметры соответствия.

Однако полученное вами сообщение об ошибке по другой причине. В отличие от C ++ в C struct_tag сам по себе не представляет тип (если бы это было так, вам бы не понадобился typedef!), Вы должны использовать ключевое слово struct.

1 голос
/ 16 ноября 2010

Вы получите сообщение об ошибке, так как не ЗНАЕТЕ размер «порта», так как все, что ему нужно - это предварительное объявление.

Таким образом, лучше не использовать здесь предварительную декларацию, если только вы не установите постоянное значение, равное размеру "struct_tag" ... Скорее всего, лучше всего полностью объявить его.

...