gpt4 book ai didi

c++ - 什么是循环包含依赖项,为什么不好,我该如何解决?

转载 作者:行者123 更新时间:2023-12-01 23:08:28 24 4
gpt4 key购买 nike

假设我有两个相互引用的数据结构。我想像这样将它们放入单独的头文件中:

 // datastruct1.h
#ifndef DATA_STRUCT_ONE
#define DATA_STRUCT_ONE

#include <datastruct2.h>
typedef struct DataStructOne_t
{
DataStructTwo* two;
} DataStructOne;
#endif

 // datastruct2.h
#ifndef DATA_STRUCT_TWO
#define DATA_STRUCT_TWO

#include <datastruct1.h>
typedef struct DataStructTwo_t
{
DataStructOne* one;
} DataStructTwo;

#endif

我有一个 main 函数:

 #include <datastruct1.h>
#include <datastruct2.h>

int main()
{
DataStructOne* one;
DataStructTwo* two;
}

但是我的编译器提示:

$ gcc -I. -c main.c
In file included from ./datastruct1.h:4,
from main.c:1:
./datastruct2.h:8:2: error: unknown type name ‘DataStructOne’
8 | DataStructOne* one;
| ^~~~~~~~~~~~~

这是为什么呢?我该怎么做才能解决这个问题?

最佳答案

为什么?

为了理解原因,我们需要像编译器一样思考。让我们在分析 main.c 时这样做逐行。编译器会做什么?

  • #include <datastruct1.h> : 把“main.c”放在一边(压入正在处理的文件栈),切换到“datastruct1.h”
  • #ifndef DATA_STRUCT_ONE : 嗯,这还没有定义,让我们继续。
  • #define DATA_STRUCT_ONE : 好的,定义了!
  • #include <datastruct2.h> : 将“datastruct1.h”放在一边,切换到“datastruct2.h”
  • #ifndef DATA_STRUCT_TWO : 嗯,这还没有定义,让我们继续。
  • #define DATA_STRUCT_TWO : 好的,定义了!
  • #include <datastruct1.h> : 将“datastruct2.h”放在一边,切换到“datastruct1.h”
  • #ifndef DATA_STRUCT_ONE :现在已经定义,所以直接转到#endif .
  • (end of "datastruct1.h") :关闭“datastruct1.h”并从填充堆栈中弹出当前文件。我在做什么?啊,“datastruct2.h”。我们从离开的地方继续。
  • typedef struct DataStructTwo_t好的,开始结构定义
  • DataStructOne* one; 等等,什么是DataStructOne ? 我们没见过吧? (查看已处理行的列表)不,不 DataStructOne洞察力。 panic !

发生了什么事?为了编译“datastruct2.h”,编译器需要“datastruct1.h”,但是 #include “datastruct1.h”中的守卫阻止其内容实际包含在需要的地方。

情况是对称的,所以如果我们调换 #include 的顺序“main.c”中的指令,我们得到相同的结果,但两个文件的角色相反。我们也不能删除守卫,因为那样会导致无限文件包含链。

看来我们需要“datastruct2.h”出现在“datastruct1.h”之前并且我们需要“datastruct1.h”出现在“datastruct2.h”之前。这似乎不可能。

什么?

文件A的情况#include s文件B依次为#include s 文件 A 显然是 Not Acceptable 。我们需要打破恶性循环。

幸运的是,C 和 C++ 有前向声明。我们可以使用这个语言特性来重写我们的头文件:

 #ifndef DATA_STRUCT_ONE
#define DATA_STRUCT_ONE

// No, do not #include <datastruct2.h>
struct DataStructTwo_t; // this is forward declaration

typedef struct DataStructOne_t
{
struct DataStructTwo_t* two;
} DataStructOne;
#endif

在这种情况下,我们可以用同样的方式重写“datastruct2.h”,消除它对“datastruct1.h”的依赖,在两个处打破循环(严格来说,这是不需要的,但较少的依赖总是好的)。唉。这并非总是如此。通常只有一种方法可以引入前向声明并打破循环。例如,如果,而不是

DataStructOne* one;

我们有

DataStructOne one; // no pointer

那么前向声明在这个地方是行不通的。

如果我无法在任何地方使用前向声明怎么办?

那么你有一个设计问题。例如,如果不是 both DataStructOne* one;DataStructTwo* two;你有DataStructOne one;DataStructTwo two; ,那么这个数据结构在 C 或 C++ 中是不可实现的。您需要将其中一个字段更改为指针(在 C++ 中:智能指针),或者完全消除它。

关于c++ - 什么是循环包含依赖项,为什么不好,我该如何解决?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70350116/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com