Разрешить круговую зависимость от определения типа?

В случае, если кто-либо в OS X имеет эту проблему, mysql, установленный с homebrew, имеет выход по умолчанию, расположенный в /usr/local/var/mysql/database-name/

33
задан Nick Van Brunt 20 May 2009 в 14:58
поделиться

6 ответов

Вперед объявите одну из структур:


struct people;

typedef struct {
  /* same as before */
  struct people* friends;
} Person;

typedef struct people {
  /* same as before */
} People;
28
ответ дан 27 November 2019 в 17:51
поделиться
struct People_struct;

typedef struct {
    char* name;
    int age;
    int lefthanded;
    struct People_struct* friends;
} Person;

typedef struct People_struct {
    int count;
    int max;
    Person data[];
} People;
0
ответ дан 27 November 2019 в 17:51
поделиться
struct _People;

typedef struct {
    char* name;
    int age;
    int lefthanded;
    struct _People* friends;
} Person;

struct _People {
    int count;
    int max;
    Person data[1];
};

Примечание. Являются ли персональные данные []; стандартными?

1
ответ дан 27 November 2019 в 17:51
поделиться

Что касается удобочитаемости:

typedef struct Foo_ Foo;
typedef struct Bar_ Bar;

struct Foo_ {
    Bar *bar;
};

struct Bar_ {
    Foo *foo;
};

Было бы неплохо вообще избежать typedef struct ;

6
ответ дан 27 November 2019 в 17:51
поделиться

Поскольку Person просто хочет указать указатель на People , можно просто заранее объявить последнее:

typedef struct People People;

Затем измените второе объявление на просто объявите с помощью тега структуры, например:

struct People {
    int count;
    int max;
    Person data[];
};
2
ответ дан 27 November 2019 в 17:51
поделиться

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

typedef struct Person Person;
typedef struct People People;

struct Person {
    char* name;
    int age;
    int lefthanded;
    People* friends;
};

struct People {
    int count;
    int max;
    Person* data;
};

Обратите внимание на добавление двух «пустых» определений типов вверху (объявлений). Это сообщает компилятору, что новый тип Person относится к типу struct Person, поэтому, когда он видит это внутри определения struct People, он знает, что это означает.

В вашем конкретном случае вам действительно можно было бы обойтись только предварительно объявив Typdef People, потому что это единственный тип, используемый до его определения. К тому времени, когда вы перейдете к определению структуры People, вы уже полностью определили тип Person.Таким образом, следующее также будет работать, но НЕ РЕКОМЕНДУЕТСЯ , потому что оно хрупкое:

typedef struct People People;

typedef struct {
    char* name;
    int age;
    int lefthanded;
    People* friends;
} Person;

struct People {
    int count;
    int max;
    Person* data;
};

Если вы поменяете порядок определений структур (перемещение структуры People выше typedef для Person), она снова потерпит неудачу. Это делает его хрупким и поэтому не рекомендуется.

Обратите внимание, что этот трюк НЕ работает, если вы включаете структуру указанного типа, а не указатель на нее. Так, например, следующий НЕ БУДЕТ компилироваться :

typedef struct Bar Bar;

struct Foo
{
    Bar bar;
};

struct Bar
{
    int i;
};

Приведенный выше код выдает ошибку компилятора, потому что тип Bar является неполным, когда он пытается использовать его внутри определения struct Foo. Другими словами, он не знает, сколько места выделить для элемента структуры bar, потому что на тот момент он не видел определения struct bar.

Этот код скомпилирует :

typedef struct Foo Foo;
typedef struct Bar Bar;
typedef struct FooBar FooBar;

struct Foo
{
    Bar *bar;
};

struct Bar
{
    Foo *foo;
};

struct FooBar
{
    Foo     foo;
    Bar     bar;
    FooBar  *foobar;
};

Это работает даже с круговыми указателями внутри Foo и Bar, потому что типы «Foo» и «Bar» были предварительно объявлены (но еще не определены ), чтобы компилятор мог построить на них указатель.

К тому времени, когда мы подошли к определению FooBar, мы определили размер как Foo, так и Bar, чтобы мы могли включить туда фактические объекты. Мы также можем включить ссылочный указатель на тип FooBar, потому что мы заранее объявили этот тип.

Обратите внимание, что если вы переместите определение struct FooBar над определениями struct Foo или Bar, оно не будет компилироваться по той же причине, что и в предыдущем примере (неполный тип).

43
ответ дан 27 November 2019 в 17:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: