Как разрешить циклические структурные зависимости в C - PullRequest
1 голос
/ 10 февраля 2020

Итак, у меня есть две структуры, которые для простоты мы будем называть A и B. A содержит указатель на B, а B содержит A. Итак, вот код:

ах

#ifndef A_H
#define A_H

#include "b.h"

typedef struct _A {
    B *b;
} A;

#endif

чч

#ifndef B_H
#define B_H

#include "a.h"

typedef struct _B {
    A a;
} B;

#endif

Теперь проблема в том, что когда я импортирую ах из моего основного c файла, я получить ошибки о том, что A является неизвестным типом от bh, я не уверен, как решить эту проблему.

Ответы [ 4 ]

6 голосов
/ 10 февраля 2020

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

typedef struct _A A;
typedef struct _B B;

typedef struct _A {
    B *b;
} A;

typedef struct _B {
    A a;
} B;

Вы можете поместить предопределения в глобальный включаемый файл для включения из любого места.

`

2 голосов
/ 10 февраля 2020

Вы должны понимать разницу между декларацией и определением. На данный момент я отложил typedef в сторону. Чтобы иметь возможность сделать это определение :

struct A {
    struct B *b;
};

, вы должны ПЕРВЫЙ объявить struct B. Обратите внимание, что если вы объявили что-то перед определением, определение считается как определением, так и объявлением. Но в этом случае из-за циклической зависимости нам нужны отдельные объявления. Вы можете решить это с помощью:

struct A;
struct B;

Эти две строки в основном говорят: «существует две структуры, и их имена A и B».

В большинстве случаев предпочтительным решением будет примерно так:

ах

#ifndef A_H
#define A_H
typedef struct A A;
#endif

аналогично для чч

а. c

#include "a.h"
#include "b.h"

struct A {
    struct B* B;
};

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

Я написал соответствующий ответ на эту топи c: { ссылка }

1 голос
/ 10 февраля 2020

Объявите struct _B и удалите #incude "b.h" в a.h.

С a.h содержит только указатель на B ему не нужно знать, что это за структура данных, поэтому в A нам нужно только объявить его имя.

Живой образец

ах

#ifndef A_H
#define A_H

struct _B;

typedef struct _A {
    struct _B* b;
} A;

#endif

чч

#ifndef B_H
#define B_H

#include "a.h"

typedef struct _B {
    A a;
} B;

#endif
1 голос
/ 10 февраля 2020

Вот решение, в котором ни один заголовок не должен знать тег структуры, используемый другим заголовком. (В частности, struct B в B.h можно изменить на struct foo без изменений в A.h. И A.h вообще не нуждается в теге; struct A можно удалить.) Это решение также позволяет Исходный файл должен включать заголовок или оба заголовка в любом порядке.

A.h может быть:

#include "B.h"

#if !defined A_h
#define A_h

typedef struct A
{
    B *b;
} A;

#endif  //  #if !defined A_h

и B.h может быть:

#if !defined B_h
#define B_h

typedef struct B B;

#include "A.h"

typedef struct B
{
    A a;
} B;

#endif  //  #if !defined B_h

B.h работает путем выполнения частичного (неполного) определения B, в котором структура известна только по тегу, а не по содержимому. Затем он включает A.h для получения полной информации о A, которая использует B только по указателю (что разрешено для неполных структурных типов). B.h завершается полным объявлением B.

A.h работает, гарантируя, что B.h включается первым. Он делает это перед защитой заголовка, чтобы включение A.h в B.h полностью включало A.h, что B.h необходимо.

...