防止递归 C #include

发布于 2024-08-17 04:22:04 字数 311 浏览 4 评论 0原文

我大致了解 #include 对 C 预处理器所做的规则,但我并不完全理解它。现在,我有两个头文件,Move.h 和 Board.h,它们都 typedef 各自的类型(Move 和 Board)。在两个头文件中,我需要引用另一个头文件中定义的类型。

现在我在 Board.h 中有#include“Move.h”,在 Move.h 中有#include“Board.h”。当我编译时,gcc 翻转并给我一个很长的(看起来像无限递归的)错误消息,在 Move.h 和 Board.h 之间翻转。

如何包含这些文件,以便我不会无限期地递归包含?

I roughly understand the rules with what #include does with the C preprocessor, but I don't understand it completely. Right now, I have two header files, Move.h and Board.h that both typedef their respective type (Move and Board). In both header files, I need to reference the type defined in the other header file.

Right now I have #include "Move.h" in Board.h and #include "Board.h" in Move.h. When I compile though, gcc flips out and gives me a long (what looks like infinite recursive) error message flipping between Move.h and Board.h.

How do I include these files so that I'm not recursively including indefinitely?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

海的爱人是光 2024-08-24 04:22:04

您需要查看前向声明,您已经创建了包含的无限循环,前向声明是正确的解决方案。

下面是一个例子:

Move.h

#ifndef MOVE_H_
#define MOVE_H_

struct board; /* forward declaration */
struct move {
    struct board *m_board; /* note it's a pointer so the compiler doesn't 
                            * need the full definition of struct board yet... 
                            * make sure you set it to something!*/
};
#endif

Board.h

#ifndef BOARD_H_
#define BOARD_H_

#include "Move.h"
struct board {
    struct move m_move; /* one of the two can be a full definition */
};
#endif

main.c

#include "Board.h"
int main() { ... }

注意:每当你创建一个“Board”时,你都需要做这样的事情(有几种方法,这里是一个例子):

struct board *b = malloc(sizeof(struct board));
b->m_move.m_board = b; /* make the move's board point 
                        * to the board it's associated with */

You need to look into forward declarations, you have created an infinite loops of includes, forward declarations are the proper solution.

Here's an example:

Move.h

#ifndef MOVE_H_
#define MOVE_H_

struct board; /* forward declaration */
struct move {
    struct board *m_board; /* note it's a pointer so the compiler doesn't 
                            * need the full definition of struct board yet... 
                            * make sure you set it to something!*/
};
#endif

Board.h

#ifndef BOARD_H_
#define BOARD_H_

#include "Move.h"
struct board {
    struct move m_move; /* one of the two can be a full definition */
};
#endif

main.c

#include "Board.h"
int main() { ... }

Note: whenever you create a "Board", you will need to do something like this (there are a few ways, here's an example):

struct board *b = malloc(sizeof(struct board));
b->m_move.m_board = b; /* make the move's board point 
                        * to the board it's associated with */
七度光 2024-08-24 04:22:04

包括警卫将是解决此问题的一部分。

维基百科的示例:

#ifndef GRANDFATHER_H
#define GRANDFATHER_H

struct foo {
    int member;
};

#endif

http://en.wikipedia.org/wiki/Include_guard

另一部分正如其他几个人所指出的那样,这是前向引用。 (http://en.wikipedia.org/wiki/Forward_Reference)

您可以部分声明一个另一个结构之上的结构如下:

#ifndef GRANDFATHER_H
#define GRANDFATHER_H

struct bar;
struct foo {
    int member;
};

#endif

Include guards would be part of the solution to this issue.

Example from wikipedia:

#ifndef GRANDFATHER_H
#define GRANDFATHER_H

struct foo {
    int member;
};

#endif

http://en.wikipedia.org/wiki/Include_guard

The other part as noted by several others is forward referencing. (http://en.wikipedia.org/wiki/Forward_Reference)

You can partially declare one of the structures above the other one like so:

#ifndef GRANDFATHER_H
#define GRANDFATHER_H

struct bar;
struct foo {
    int member;
};

#endif
埋葬我深情 2024-08-24 04:22:04

像这样:

//Board.h
#ifndef BOARD_H
#define BOARD_H
strunct move_t; //forward declaration
typedef struct move_t Move;
//...
#endif //BOARD_H

//Move.h
#ifndef MOVE_H
#define MOVE_H
#include "Move.h"
typedef struct board_t Board;
//...
#endif //MOVE_H

这样 Board.h 可以在不依赖 move.h 的情况下编译,并且您可以包含 move 中的 board.h .h 使其内容在那里可用。

Like so:

//Board.h
#ifndef BOARD_H
#define BOARD_H
strunct move_t; //forward declaration
typedef struct move_t Move;
//...
#endif //BOARD_H

//Move.h
#ifndef MOVE_H
#define MOVE_H
#include "Move.h"
typedef struct board_t Board;
//...
#endif //MOVE_H

This way Board.h can be compiled without dependency on move.h and you can include board.h from move.h to make its content available there.

往昔成烟 2024-08-24 04:22:04

首先,您的 .h 文件中似乎缺少 includeguards ,所以你递归地包含它们。那很糟糕。

其次,您可以进行前瞻性声明。在 Move.h 中:

/* Include guard to make sure your header files are idempotent */
#ifndef H_MOVE_
#define H_MOVE_

#include "Board.h"

/* Now you can use struct Board */
struct Move { struct Board *board; };

#endif

Board.h 中:

#ifndef H_BOARD_
#define H_BOARD_

struct Move; /* Forward declaration.  YOu can use a pointer to
                struct Move from now on, but the type itself is incomplete,
                so you can't declare an object of the type itself. */
struct Board { struct Move *move; }; /* OK: since move is a pointer */

#endif

请注意,如果需要声明 struct Movestruct Board如果两个文件中都存在对象(而不是指向其中之一的指针),则此方法将不起作用。这是因为在解析其中一个文件时,其中一种类型是不完整类型(上例中的struct Move)。

因此,如果您需要使用这两个文件中的类型,则必须分离出类型定义:具有定义 struct Movestruct Board 的头文件,以及没有别的(就像我上面的例子一样),然后使用另一个引用 struct Movestruct Board 的头文件。

当然,您不能让 struct Move 包含 struct Board 并且 struct Board 包含 struct Move同时,这将是无限递归,并且结构大小也将是无限的!

First, you seem to lack include guards in your .h files, so you're including them recursively. That is bad.

Second, you can do a forward declaration. In Move.h:

/* Include guard to make sure your header files are idempotent */
#ifndef H_MOVE_
#define H_MOVE_

#include "Board.h"

/* Now you can use struct Board */
struct Move { struct Board *board; };

#endif

In Board.h:

#ifndef H_BOARD_
#define H_BOARD_

struct Move; /* Forward declaration.  YOu can use a pointer to
                struct Move from now on, but the type itself is incomplete,
                so you can't declare an object of the type itself. */
struct Board { struct Move *move; }; /* OK: since move is a pointer */

#endif

Note that if you need to declare struct Move and struct Board objects (rather than pointer to one of them) in both the files, this method won't work. This is because one of the types is an incomplete type at the time of parsing of one of the files (struct Move in the above example).

So, if you need to use the types in both the files, you will have to separate out the type definitions: have header files that define struct Move and struct Board, and nothing else (something like my example above), and then use another header file that references both struct Move and struct Board.

Of course, you can't have struct Move contain a struct Board and struct Board contain a struct Move at the same time—that will be infinite recursion, and the struct sizes will be infinite as well!

╄→承喏 2024-08-24 04:22:04

您首先需要拥有其中之一。在其中之一中进行前向声明,并将该声明作为例如

    #ifndef move
    struct move;
    #endif

board.h 文件的一部分。

并且

    #ifndef board
    struct board;
    #endif

可以是 move.h 文件的一部分,

然后您可以按任一顺序添加它们。

编辑
正如评论中指出的那样...我假设对板结构使用 typedef 构造如下,

   typedef struct {…} board;

因为我从未见过有人在没有 typedef 的情况下使用 C 中的结构我做了这个假设...也许事情已经改变了自从我上次用 C 编写代码以来(哎呀......那是 15 年前的事了)

You need to have one of them first. Make a forward decl in one of them and have that one for for example

    #ifndef move
    struct move;
    #endif

could be part of the board.h file.

and

    #ifndef board
    struct board;
    #endif

could be part of the move.h file

then you could add them in either order.

edit
As was pointed out in the comments... I was assuming the use of the typedef construct as follows for the board struct

   typedef struct {…} board;

since I've never seen anyone using structs in C without a typedef I made this assumption... maybe things have changed since the last time I coded in C (yikies.... it was like 15 years ago)

毁梦 2024-08-24 04:22:04

循环依赖是一件令人头疼的事,应该尽可能消除。除了到目前为止给出的前向声明建议(Alok 的就是最好的例子)之外,我还想提出另一个建议:通过引入第三种类型(将其称为 BoardMoveAssoc 进行说明)来打破 Board 和 Move 之间的相互依赖;我相信你可以想出一个不那么糟糕的名字):

#ifndef H_BOARD_MOVE_ASSOC
#define H_BOARD_MOVE_ASSOC

#include "Move.h"
#include "Board.h"

struct BoardMoveAssoc {
    Move m;
    Board b;
};

...
#endif

在这个方案下,Board 和 Move 不需要互相了解任何信息;两者之间的任何关联均由 BoardMoveAssoc 类型管理。确切的结构取决于 Move 和 Board 的关联方式;例如,如果多个动作映射到单个棋盘,则结构可能看起来更像

 struct BoardMoveAssoc {
     Move m[NUM_MOVES] // or Move *m;
     Board b;
 };

这样,您不必担心前向声明或不完整的类型。您正在将第三种类型引入其中,但我相信这会更容易理解和维护。

Circular dependencies are a pain in the ass and should be eliminated wherever feasible. In addition to the forward declaration suggestions given so far (Alok's is the best example), I'd like to throw another suggestion into the works: break the mutual dependency between Board and Move by introducing a third type (call it BoardMoveAssoc for illustration; I'm sure you can come up with a less sucky name):

#ifndef H_BOARD_MOVE_ASSOC
#define H_BOARD_MOVE_ASSOC

#include "Move.h"
#include "Board.h"

struct BoardMoveAssoc {
    Move m;
    Board b;
};

...
#endif

Under this scheme, Board and Move don't have to know anything about each other; any associations between the two are managed by the BoardMoveAssoc type. The exact structure will depend on how Move and Board are supposed to be related; e.g., if multiple moves are mapped to a single board, the structure may look more like

 struct BoardMoveAssoc {
     Move m[NUM_MOVES] // or Move *m;
     Board b;
 };

This way, you don't have to worry about forward declarations or incomplete types. You are introducing a third type into the mix, but I believe this will be easier to understand and maintain.

執念 2024-08-24 04:22:04

来自 K&R C 编程语言(我的副本中的第 91 页“条件包含”),为您做了一些调整:

#if !defined (BOARD_H)
#define BOARD_H

/* contents of board.h go here */

#endif

对于 Move.h 也是如此

,一旦包含一次标头,就不会包含它再次,因为已经为预处理器定义了“BOARD_H”名称。

From K&R The C Programming Language (p 91 "Conditional Inclusion" in my copy), with some tweaks for you:

#if !defined (BOARD_H)
#define BOARD_H

/* contents of board.h go here */

#endif

and the same for Move.h

In this way, once a header has been included once, it will not be included again, as the 'BOARD_H' name has already been defined for the preprocessor.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文