0

我在工作区中有一个带有 *.c 和 *.h 文件的纯 C 代码。
我有一个头文件 1.h 声明一些结构为

struct my1
{ 
int a;
..
..
}my_t;

但是当我尝试在另一个头文件 2.h 中声明类型为 struct my1 的变量时,如下所示: -

struct my1 variable1;

它在此声明点给出错误。

看起来 my1 在 2.h 文件中未定义。

在文件 1.h 中我需要包含 2.h,所以在文件 2.h 中我不能包含 1.h,因为担心递归包含。

我的问题是:-

  1. 在这种情况下,我需要声明什么来解决编译错误?

    这整件事让我想到了有关头文件包含的更多问题。

  2. 头文件是如何包含的,按什么顺序,先是哪个头文件,然后是哪个头文件?

  3. 头文件的递归包含会导致错误一个文件包括其他和其他包括第一个?

出于某种安全原因,无法发布实际的代码片段,如果问题在某种程度上造成了一些可读性问题,我们深表歉意。

4

7 回答 7

4

您应该首先在所有 .h 文件中放置一个包含锁(这称为包含保护):

#ifndef ONE_H
#define ONE_H

//rest of header

#endif //ONE_H

这样你就可以多次包含它。

第二:

typedef struct my1 { int a; .. .. }my_t;

您需要 C 中的 typedef(而不是 C++)

标题按包含顺序包含在内。

如果你编译一个文件 abc.c,它的开头是:

#include "a.h"
#include "b.h"

那么 ah 将首先被包括在内,然后是 bh

你可以这么想,就好像你把代码粘贴到文件里一样。它包含在这一点上。

于 2009-04-01T14:14:20.530 回答
2

就像前面的人说的那样。

我只想补充一点,有时即使#ifdef 也无济于事。

//file1.h
#ifndef F1
#define F1

#include "file2.h"

struct file1st {
  struct file2st *ptr;
};

#endif

//file2.h

#ifndef F2
#define F2

#include "file1.h"

struct file2st {
   struct file1st *ptr;
};

#endif

//main.c

#include "file1.h"
#include "file2.h"

/*
This will give you an error of **struct file1st not defined**
Let's see why: 

1) file1.h is included
2) file1.h includes file2.h before it declares anything
3) the definition of struct file2st occurs and it uses struct file1st which isn't declared yet
*/

int main(int argc, char* argv[]){
  struct file1st st1;
  struct file2st st2;

  return 0;
}

解决这个问题的方法是:

//file1.h
    #ifndef F1
    #define F1

    struct file2st;//just declare, it will be defined later. 

    struct file1st {
      struct file2st *ptr; // ok, compiler KNOWS the size of struct file2st*(pointer)
      struct file2st file2Var;// NOT ok, compiler doesn't know sizeof(struct file2st)
    };

    #endif

    //file2.h

    #ifndef F2
    #define F2

    #include "file1.h"

    struct file2st {
       struct file1st *ptr;
    };

    #endif
于 2009-04-01T15:00:37.937 回答
1

头文件按包含指令的顺序包含。一旦编译器看到包含指令,它就会打开要包含的文件并将其所有内容插入到包含文件中。

如果包含的文件内部有包含指令,则对它们执行相同的操作。这个过程一直持续到所有的包含指令都被处理完。

之后才开始编译。

这就是为什么如果任何文件被多次包含(A 包含 B 和 C;例如 B 和 C 都包含 D),您会经常看到编译器抱怨重新定义。要解决此问题,请添加包含锁(也称为include guards)- ifdef指令。

//file Header1
#ifndef Header1Guard
   #define Header1Guard
// all the header text here
#endif
于 2009-04-01T14:20:53.307 回答
1

我赞成守卫的建议。

我虔诚地使用以下标题模板:

#ifndef HELLOWORLD_H_
#define HELLOWORLD_H_

// Header stuff here.

#endif // HELLOWORLD_H_

当编译器看到#include 时,它​​只是用头文件的内容替换该行(减去头文件中任何已处理的指令)。因此,这意味着您可以在任意数量的地方包含文件,而不会冒递归包含的风险。

于 2009-04-01T14:24:10.320 回答
1

每个头文件都包含在每个翻译单元(源文件)中,其中有一个包含指令。这是有意的,并且即使使用包含保护也会发生 - 每个使用您的结构的翻译单元都需要知道该结构是如何定义的,以便它可以在您的应用程序的所有翻译单元中以相同的方式布局在内存中。包含保护只是防止它被多次包含在一个翻译单元中. 包含文件将按照您将它们包含在该翻译单元中的顺序包含在内(如果包含文件包含其他文件......正如其他人所说,它们将被递归包含)。编译的翻译单元的顺序由您(或您的 IDE)指定给编译器。然而,这个顺序是什么并不重要,因为每个翻译单元都是完全独立的,直到它进入构建过程的链接阶段。

于 2009-04-01T14:49:08.777 回答
0

自从我使用 C 以来已经有一段时间了,但我认为你想要做的是向前定义 my1。

在 2.h 中,尝试将其放在顶部附近:

struct my1;

抱歉,我无法回答你的另外两个问题。

于 2009-04-01T14:11:13.347 回答
0
// Header1.h
typedef struct tagHeader1
{
} Header1;

// Header2.h

struct Header1;

// Header2.c

#include "Header1.h"

注意:这仅适用于指针(在 c++ 中,引用)。如果您有对完整对象的引用,编译器将需要知道它。

于 2009-04-01T14:14:53.320 回答