C 头文件是如何包含的?

C 头文件是如何包含的?,c,recursion,include,header-files,C,Recursion,Include,Header Files,我在工作区中有一个带有*.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,因为担心递归包含 我的问题是:- 在这种情况下,我需要声明什么来解决编译

我在工作区中有一个带有*.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,因为担心递归包含

我的问题是:-

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

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

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

  • 头文件的递归包含是否会导致一个文件包含另一个文件和另一个文件包含第一个文件的错误


  • 由于某些安全原因,无法发布实际的代码片段,如果这个问题有一些可读性问题,那么很抱歉。

    我已经有一段时间没有使用C了,但我认为您要做的是向前定义my1

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

    struct my1;
    

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

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

    这样您就可以多次包含它

    第二:

    typedef struct my1 { int a; .. .. }my_t;
    
    您需要C语言中的typedef(而不是C++)

    标题按包含顺序包含

    如果编译一个文件abc.c,该文件以:

    #include "a.h"
    #include "b.h"
    
    那么先包括a.h,然后包括b.h

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

    // Header1.h
    typedef struct tagHeader1
    {
    } Header1;
    
    // Header2.h
    
    struct Header1;
    
    // Header2.c
    
    #include "Header1.h"
    

    注意:这只适用于指针(C++中的引用)。如果您有对完整对象的引用,编译器将需要了解它。

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

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

    然后才开始编译

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

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

    我赞成保安的建议

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

    #ifndef HELLOWORLD_H_
    #define HELLOWORLD_H_
    
    // Header stuff here.
    
    #endif // HELLOWORLD_H_
    

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

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

    就像人们之前所说的那样

    我只想补充一点,有时候即使是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
    

    @Burkhard:所以如果a.h内部包含一些c.h,那么它将首先被包含,然后是b.h,对吗?你不需要输入def。它只是简化了在声明中使用结构,因为您可以使用新名称。但是,如果有多个源文件包括各种头文件,那么头文件的包含从哪个源文件开始?您可以编译包含头(例如a.h和b.h)的文件(例如a.c和b.c)。编译a.c时从a.c开始包含,编译b.c时从b.c开始包含。现在更清楚了?但是如果有多个源文件,包括各种头文件,那么头文件从哪个源文件开始包含?这通常取决于编译器。它可能只是获取目录中的文件列表并遵循该顺序,或者使用项目或生成文件中指定的顺序。无论如何,每个源文件都是单独编译的,并且此顺序不会影响包含过程。如果不希望包含头文件,并且仅通过指针引用结构,则只需执行此操作(并且不要访问它的任何字段)。
    //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