如何包含头文件?

时间:2009-04-01 14:07:17

标签: c recursion include header-files

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

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

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

struct my1 variable1;

它在此声明点出错。

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

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

我的问题是: -

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

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

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

  3. 递归包含头文件会导致错误,包括其他文件在内的一个文件包括其他文件吗?

  4. 由于某些安全原因,无法发布实际的代码段,所以如果这个问题在某种程度上会带来一些可读性问题,那就很抱歉。

7 个答案:

答案 0 :(得分:4)

首先应在所有.h文件中加入包含锁(这称为include guard):

#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"

然后首先包括a.h,然后是b.h。

您可以想到它,就像将代码粘贴到文件中一样。它包括在那一点。

答案 1 :(得分: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

答案 2 :(得分:1)

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

如果包含的文件中包含 include 指令,则对它们执行相同操作。此过程将继续,直到所有 include 指令都已处理完毕。

之后才开始编译。

这就是为什么如果任何文件被包含多次(A包括B和C; B和C都包括D),你会经常看到编译器抱怨重新定义。要解决这个问题,请添加包含锁(又名包含警卫) - ifdef 指令。

//file Header1
#ifndef Header1Guard
   #define Header1Guard
// all the header text here
#endif

答案 3 :(得分:1)

我提出警卫建议。

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

#ifndef HELLOWORLD_H_
#define HELLOWORLD_H_

// Header stuff here.

#endif // HELLOWORLD_H_

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

答案 4 :(得分:1)

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

答案 5 :(得分:0)

我与C合作已经有一段时间,但我认为你想要做的是转发定义my1。

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

struct my1;

抱歉,我无法回答你的其他两个问题。

答案 6 :(得分:0)

// Header1.h
typedef struct tagHeader1
{
} Header1;

// Header2.h

struct Header1;

// Header2.c

#include "Header1.h"

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