C циклическая зависимость

У меня есть эта проблема с круговой зависимостью в C, я просмотрел другие вопросы по этой теме, но действительно не смог найти ответ.

У меня есть эта первая структура с именем вершина:

#ifndef MapTest_vertex_h
#define MapTest_vertex_h

#include "edgelist.h" //includes edgelist because it's needed

typedef struct 
{
    char* name;
    float x, y;
    edgelist* edges;
} vertex;

#endif

Вторая структура — это список ребер, который включается вершиной.

#ifndef edgelist_h
#define edgelist_h

#include "edge.h" //include edge, because its needed

typedef struct _edgelist
{
    edge** edges; 
    int capacity, size;
} edgelist;

//...

#endif

И затем последняя структура, та, где возникает проблема, структура края включается в список краев выше.

#ifndef MapTest_edge_h
#define MapTest_edge_h

#include "vertex.h" //needs to be included because it will be unkown otherwise

typedef struct 
{
    float weight;
    vertex* destination;
    int found; 
} edge;

#endif

Я пробовал все, что мог, форвардное объявление, использование #ifndef, #define и т. д., но не смог найти ответ.

Как я могу решить эту проблему циклической зависимости?


person Marnix v. R.    schedule 12.04.2012    source источник
comment
В C11 вы можете безвредно повторять определения типов. Вы можете написать typedef struct edge edge;typedef struct vertex vertex;typedef struct edgelist edgelist; в любом или во всех заголовках, а затем просто определить информацию о типе структуры (без префикса typedef или имени в конце) в соответствующем заголовке: struct vertex { … };struct edge { … };struct edgelist { … };. Однако это не будет работать в C99 или C90; определение typedef для того же имени является ошибкой в ​​более ранних версиях C.   -  person Jonathan Leffler    schedule 08.03.2017


Ответы (3)


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

#ifndef MapTest_vertex_h
#define MapTest_vertex_h

struct edgelist;

typedef struct
{
    char* name;
    float x, y;
    edgelist* edges;    // C++ only - not C
} vertex;

#endif

и т. д. В кодировании C вы должны написать:

struct edgelist;

typedef struct
{
    char* name;
    float x, y;
    struct edgelist* edges;
} vertex;
person Andreas Brinck    schedule 12.04.2012

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

1.

typedef struct 
{
    char* name;
    float x, y;
    struct _edgelist* edges; /* add "struct" here (elaborated type specifier) */
} vertex;

2.

struct __edgelist; /* better form: forward declaration */

typedef struct 
{
    char* name;
    float x, y;
    struct _edgelist* edges; /* still need to add "struct" here */
} vertex;
person Potatoswatter    schedule 12.04.2012
comment
Обратите внимание, что символы, начинающиеся с подчеркивания, за которым следует либо другое подчеркивание, либо заглавная буква, безусловно зарезервированы для использования «реализацией». В общем, избегайте создания имен, начинающихся со знака подчеркивания. - person Jonathan Leffler; 08.03.2017

Я предполагаю, что вершине нужно знать, какие ребра с ней соединяются, а ребро должно знать, с какими вершинами оно соединяется.

Если бы это зависело от меня, я бы создал отдельные типы данных для связывания вершин и ребер:

struct vertex {
  char *name;
  float x, y;
};

// edgelist as before

struct edge {
  float weight;
  int found;
};

// New struct to map edges and vertices

struct vertexEdge { // you can probably come up with a better name
  struct vertex *v;
  struct edgelist *edges;
};

// New struct to map vertices and edges

struct edgeVertext {
{
  struct edge *e;
  struct vertex *vertices;
};

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

person John Bode    schedule 12.04.2012