【问题标题】:C circular dependencyC循环依赖
【发布时间】:2012-04-24 17:49:35
【问题描述】:

我在 C 中遇到了循环依赖的问题,我查看了有关此主题的其他问题,但真的找不到答案。

我有第一个名为 vertex 的结构:

#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 等,但找不到答案。

如何解决这个循环依赖问题?

【问题讨论】:

  • 在 C11 中,您可以无害地重复 typedef。您可以在任何或所有标题中写入typedef struct edge edge;typedef struct vertex vertex;typedef struct edgelist edgelist;,然后在相关标题中简单地定义结构类型信息(不带typedef前缀或末尾的名称):@987654330 @ — struct edge { … };struct edgelist { … };。但是,这在 C99 或 C90 中不起作用;在早期版本的 C 中,为同名定义 typedef 是一个错误。

标签: c include c-preprocessor circular-dependency


【解决方案1】:

似乎您不需要在任何文件中包含任何内容。相关类型的前向声明就足够了:

#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;

【讨论】:

    【解决方案2】:

    使用前向声明可以打破这种依赖关系。除了包含具有结构完整定义的文件之外,还有两种选择:

    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;
    

    【讨论】:

    • 请注意,以下划线开头的符号后跟另一个下划线或大写字母无条件保留供“实现”使用。一般来说,避免创建以下划线开头的名称。
    【解决方案3】:

    我假设一个顶点需要知道哪些边连接到它,而一条边需要知道它连接到哪些顶点。

    如果由我决定,我会创建单独的数据类型来关联顶点和边:

    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 小时,所以我很确定有更好的方法来设计映射类型(可能不需要超过一种类型),但这是我会采取的一般方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-04
      • 2019-04-03
      • 2011-04-30
      • 1970-01-01
      • 2011-03-23
      • 2021-09-18
      • 2011-07-11
      • 1970-01-01
      相关资源
      最近更新 更多