【问题标题】:Circular dependency between struct and function in CC中结构和函数之间的循环依赖
【发布时间】:2020-11-04 22:35:10
【问题描述】:

我有以下文件:

啊.h

#ifndef __A_H_
#define __A_H_

#include <B.h> // contains foo_t
typedef struct {
     foo_t foo;
     ...
} baz_t;

#endif

B.h

#ifndef __B_H_
#define __B_H_

#include <A.h> // contains baz_t
typedef struct {
     ...
} foo_t;

extern int useful_func(baz_t d);

#endif

当我编译这个 B.h 拒绝编译抱怨 error: unknown type name 'baz_t'

我假设这个错误是由于两个文件之间的循环依赖造成的。但我想知道如何转发声明baz_t 来解决这个问题?我找到了与结构之间的循环依赖相关的答案。但我不确定我将如何解决这个问题。我会很感激这里的一些帮助。我正在寻找一个严格的 C99 解决方案。

编辑

  1. 我之前忘记提及这一点,但我已经使用了包含防护。
  2. 用户 KamilCuk 建议的一个非常明显的解决方案是将 useful_func 移动到 A.h。这也发生在我身上,但软件组织明智useful_func 不幸属于B.h。这个问题也可能是设计不佳的反映。

【问题讨论】:

  • extern int useful_func(baz_t d); 移动到 A.h 并从 B.h 中删除 #include &lt;A.h&gt; - 问题已解决。
  • 1) 我希望您使用的是#include guards。 2)您不需要“extern”限定词;原型int useful_func(baz_t d); 就足够了。 3) System headers 使用 #include&lt;some_standard_header.h&gt; 语法。您可能需要双引号 - #include "xyz.h"
  • 嗨@KamilCuk,你是绝对正确的,但我现在添加了一个编辑部分,提到了为什么我没有采用这种方法。
  • 创建一个新标头"useful_func.h",其中包含useful_func 的extern(并包含必要的标头)。这也将允许“B.h”不再包含“A.h”。

标签: c struct c99 circular-dependency


【解决方案1】:

您可以如下使用前向声明:

struct foo;

typedef struct {
    struct foo foo;
    ...
} baz_t;

然后在B.h上正常使用

也就是说,如果您在用作接口的第三个标头上定义所有内容,则可以避免循环依赖。它会更干净,但并不总是可能的。

【讨论】:

  • 如果struct 包含指向foo 的指针,这将起作用。但是前向声明不足以将foo 本身用作成员或参数类型,或者任何其他需要foo 的大小和内容的东西。
【解决方案2】:

通常,人们会将指针传递给结构,而不是按值传递它们。如果这是可以接受的,事情就简单了,因为 C 编译器会接受声明:

void doSomethingWithAFoo(struct foo *it);

不管他们是否见过struct foo 的任何定义。事实上,编译器甚至会接受函数定义,例如:

void doSomethingWithAFooTwice(struct foo *it)
{
  doSomethingWithAFoo(it);
  doSomethingWithAFoo(it);
}

无需知道或关心struct foo 是否、在哪里或如何定义。

请注意,使用struct tag 语法而不是 typedef 名称的一个优点是,使用 struct 标记语法的原型不需要声明或定义任何不能无害地任意多次重新声明的内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-30
    • 2019-04-30
    • 2020-12-20
    相关资源
    最近更新 更多