Почему не работает предварительное объявление структуры?

Я написал небольшой код на C, в котором были определены два типа структур, в определении которых есть члены друг друга. Случай 1: если структура foo определена до структуры bar, код компилируется, как и ожидалось. Случай 2: если struct foo определена после struct bar, она не будет скомпилирована, что также ожидается, поскольку невозможно узнать требования к памяти для переменной struct foo. Но я ожидал, что он скомпилируется, если в случае 2 используется предварительное объявление struct foo. Но это не работает. Что мне не хватает?

#include<stdio.h>
#include<stdlib.h>

struct foo; // forward declaration

struct bar
{
  int a;
  struct bar *next;
  struct foo ch;
};

struct foo
{
  struct bar *n;
  struct foo *nx;
};


int main()
{
  struct bar p;
  return(0);
}

person anupamb    schedule 05.06.2014    source источник
comment
Предварительное объявление по-прежнему ничего не знает о требованиях к памяти foo.   -  person Michael Ivko    schedule 05.06.2014
comment
поменять местами foo и bar. вперед объявить бар. struct foo ch требует, чтобы foo было полностью определено, struct bar * n требует только объявления бара   -  person Erik    schedule 05.06.2014
comment
Если foo и bar поменялись местами, предварительное объявление bar не требуется, так как члены foo являются типами данных указателя.   -  person anupamb    schedule 05.06.2014


Ответы (4)


предварительное объявление только информирует компилятор о том, что есть что-то, что называется foo, оно ничего не говорит о размере. вы можете использовать foo*, так как это указатель известного размера, но не сам foo, потому что размер неизвестен, поэтому компилятор не знает, как должна выглядеть структура памяти bar.

И компилятор делает только один проход через ваш документ. поэтому он не может знать структуру, которая определена заранее.

person vlad_tepesch    schedule 05.06.2014
comment
Спасибо! Я получаю это сейчас. - person anupamb; 05.06.2014

Если тип структуры X появляется только как тип указателя в объявлении структуры или ее функциях, а код в заголовочном файле не пытается получить доступ к каким-либо переменным-членам X, то вы не должны #include Xh, а вместо этого сделать неполный объявление X (также называемое «упреждающим» объявлением) перед первым использованием X. Вот пример, в котором тип структуры Thing ссылается на X с помощью указателя:

struct X;  /* incomplete ("forward") declaration */

struct Thing {
  int i;
  struct X* x_ptr;
};

Компилятор будет рад принять код, содержащий указатели на не полностью известный тип структуры, в основном потому, что указатели всегда имеют одинаковый размер и характеристики независимо от того, на что они указывают. Как правило, доступ к членам (или размеру) X требуется только коду в файле .c, поэтому файл .c будет #include "X.h". Это мощная техника для инкапсуляции модуля и отделения его от других модулей.

То есть он будет работать правильно, если ваш код будет выглядеть примерно так:

#include<stdio.h>
#include<stdlib.h>

struct foo; // forward declaration

struct bar
{
  int a;
  struct bar *next;
  struct foo *ch;       /* MODIFIED LINE */
};

struct foo
{
  struct bar *n;
  struct foo *nx;
};


int main()
{
  struct bar p;
  return(0);
}

Но в вашем случае struct bar имеет «элемент» типа struct foo. Следовательно, это даст поле ошибки неполного типа.

Также для информации см. приведенный ниже фрагмент (идеально работает):

#include<stdio.h>
#include<stdlib.h>

struct bar
{
  int a;
  struct aabar *next;  /* MODIFIED LINE - aabar never declared */
  struct foo *ch;
};

struct foo
{
  struct bar *n;
  struct foo *nx;
};

int main()
{
  struct bar p;
  return(0);
}
person Arjun Mathew Dan    schedule 08.10.2014

Объявление также не может сообщить компилятору, как выделить память.

person wangsquirrel    schedule 05.06.2014

В вашем struct foo элемент nx является указателем, поэтому определение struct foo не требует размера памяти. Однако в struct bar элемент ch не является указателем, поэтому определяющему struct bar необходимо знать размер struct foo. В предварительном объявлении не указывается размер памяти, а в определении.

person Thanushan    schedule 05.06.2014