【问题标题】:Solving a circular dependency - C解决循环依赖 - C
【发布时间】:2013-02-04 04:20:56
【问题描述】:

我检查了 SO 是否有重复项,但无法为我的问题找到确切的解决方案。

我有一个头文件NvCommon.h,我在其中使用枚举NV_DATA_TYPE。这个枚举在另一个头文件NvDefs.h 中定义,我使用了来自NvCommon.h 的一些结构和枚举。由于循环依赖,我无法构建它。我知道forwrd declaring enum 是不可能的。

在这种情况下可以做什么?这是我设计的问题吗?是不是必须要引入另一个头文件才能解决这个问题?

我不是 C 专家。请帮我。我的设计可能有问题,我知道可以通过引入另一个头文件来解决这种循环依赖。我想知道的是“这是唯一的方法”。寻找替代解决方案(如果有)。

如果有帮助,我会发布完整的代码。

【问题讨论】:

  • 将枚举放在单独的文件上就可以了。
  • 或者,将enum NV_DATA_TYPE的定义移动到NvCommon.h
  • 或者,提供您的代码,以便我们轻松重现问题。
  • 您能否确认您是否在所有头文件中都包含了保护措施
  • @camelccc:谢谢。警卫在场。

标签: c


【解决方案1】:

在它们自己的文件中定义枚举会很有用,如果你在这里这样做,你的问题就会消失。

【讨论】:

  • 谢谢。如果没有更好的选择,我会这样做。
【解决方案2】:

如果我正确理解你的问题,你会得到这样的:

derpfoo.h:

#ifndef DERPFOO_H
#define DERPFOO_H

#include "derpbar.h"

typedef struct {
        char *nothing;
} FOO;

BAR foo (BAR derp) {
        return derp;
}

#endif

derpbar.h:

#ifndef DERPBAR_H
#define DERPBAR_H

#include "derpfoo.h"

typedef struct {
        char *nothing;
} BAR;

FOO bar (FOO derp) {
        return derp;
}

#endif

然后是一个简单的derp.c:

#include "derpfoo.h"
#include "derpbar.h"

int main (void) {
        return 0;
}

我的一个朋友不久前在一些 SDL 代码中向我提出了这个问题,我花了一段时间才明白他为什么要这样做,以及如何合理地解决它。

这样分离代码的目的是 derpfoo 和 derpbar 在逻辑上是分开的,但遗憾的是,它们也是相互依赖的。对于这样的事情,我发现的最简单的解决方案是将它们组合起来并根据解剖结构而不是像这样的逻辑来拆分它们:

derpstructs.h:

#ifndef DERPSTRUCTS_H
#define DERPSTRUCTS_H

typedef struct {
        char *nothing;
} FOO;

typedef struct {
        char *nothing;
} BAR;

#include "derpfunctions.h"

#endif

derpfunctions.h:

#ifndef DERPFUNCTIONS_H
#define DERPFUNCTIONS_H

#include "derpstructs.h"

BAR foo (BAR derp) {
        return derp;
}

FOO bar (FOO derp) {
        return derp;
}

#endif

仍然是一个简单的derp.c:

#include "derpstructs.h"
#include "derpfunctions.h"

int main (void) {
        return 0;
}

请注意,derpstructs.h 在末尾​​em>而不是在开头包含 derpfunctions.h。严格来说,这不是必需的,但如果您确实打算让它们相互包含,则必须在所有可能的包含路径中包含它们所依赖的结构定义之后的函数定义。继续……

这个解决方案有效,但它并没有完全坚持导致问题开始的原始理念——这两个部分在逻辑上是分开的,应该在代码中保持这种状态。

两者的答案是进一步拆分所有内容,并进一步调整包含路径。

derpfoostructs.h 包括 derpbarstructs.h 首先 然后定义 struct FOO 然后 最后 可选地包括 derpfoofunctions.h 和 derpbarfunctions.h。

derpbarstructs.h 包含derpfoostructs.h 首先然后定义struct BAR,然后在最后可选地包含derpfoofunctions.h和derpbarfunctions.h。

derpfoofunctions.h 包含derpfoostructs.h 和derpbarstructs.h 首先,然后包含derpbarfunctions.h,然后定义其函数。

derpbarfunctions.h 包含derpfoostructs.h 和derpbarstructs.h 首先,然后包含derpfoofunctions.h,然后定义其函数。

derp.c 包括derpfoostructs.h 和derpbarstructs.h 然后 包括derpfoofunctions.h 和derpbarfunctions.h,然后继续做它需要做的任何其他事情。

这满足了两个期望的要求。它消除了循环依赖,并且仍然保持两个逻辑分离的代码单元的逻辑分离。当您从一个项目更改为另一个项目时,您需要编辑两个文件而不是一个,但它至少使可变代码与不可变代码分开。那是我找到的唯一解决方案。

希望这会有所帮助。祝你的项目好运。

【讨论】:

  • @NeonGlow 如果您需要更多详细信息或只是四包含解决方案的代码转储,请告诉我。真正的关键是考虑如果它是一个文件,它将如何流动,并意识到 C 预处理器确实如此,然后编译器得到它。因此,您可以将您的代码完全疯狂地拆分,只要包含路径将它们全部重新组合成编译器可以阅读的内容。
  • 没关系。这里有足够的输入。我可能会做作业重新排序。:)
【解决方案3】:

循环依赖可能意味着您过度设计了界面。将两个文件合并到 Nv.h 中。如果这很容易解决问题,这意味着您设计的界面不正确。

【讨论】:

  • 文件 NvCommon.h 包含不会跨项目更改的定义,而 NvDefs.h 包含将/可能会跨项目更改的内容。这就是这种划分的原因。
  • 在这种情况下,您可能想要订购东西,因此 NvDefs.h 包含 NvCommon.h 为什么您要包含文件中不会更改为会更改的内容?
  • 如果 NV_DATA_TYPE 在项目基础上发生更改,则不应将其用于在项目中应保持不变的定义中。所以NV_DATA_TYPENvCommon.h 中使用。
【解决方案4】:

Check this out

如何正确声明和定义变量、库、函数等。这可能是相关的。

【讨论】:

  • 谢谢。我正在检查这个。
【解决方案5】:

我尝试根据您的描述对这个问题进行建模。在我的实现中,我测试了三件事(1)在 NvDefs.h 中声明但未定义 NV_DATA_TYPE,(2)在 NvDefs.h 中声明和定义 NV_DATA_TYPE,以及(3)在 NvDefs.h 中定义 NV_DATA_TYPE,但将其声明为 NvCommon.h .此外,正如您提供的描述,我在 NvCommon.h 中创建了一些结构并在 NvDefs.h 中访问了这些对象。在每一种情况下——无论在头文件中是否有保护——代码编译和执行的结果都是正确的。

除了 NV_DATA_TYPE 枚举之外,您的循环依赖项是否可能位于头文件中的其他位置?

【讨论】:

  • 问题出在这两个标题中。移动枚举本身将解决问题。唯一阻止我这样做的是枚举在逻辑上不适合那里。
猜你喜欢
  • 2012-03-09
  • 2020-11-12
  • 1970-01-01
  • 2010-10-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多