周游C语言教程18 - 头文件
这是周游C语言的第十八篇教程,你将在这篇文章里学会怎么使用头文件。
头文件
头文件就是后缀名为.h
的文件,我们通常会在头文件中定义各种函数声明,宏定义,结构体定义。头文件可以被多个源文件(后缀名为.c
)引用,使用#include
即可饮用头文件。引用头文件的本质将头文件中的内容复制到源文件中。因此当多个源文件都需要使用相同内容时,就可以将这些内容写进头文件中。
引用头文件
假设头文件《header.h》中的内容如下
char func();
我们在源文件中对其进行引用
#include <stdio.h>
#include "header.h"
int main()
{
func();
return 0;
}
char func()
{
printf("func is run\n");
return 0;
}
就相当于如下代码
#include <stdio.h>
char func();
int main()
{
func();
return 0;
}
char func()
{
printf("func is run\n");
return 0;
}
当我们把#include "header.h"
移到main函数下方就会造成编译器报错,因为func函数还没有被声明。
#include <stdio.h>
int main()
{
func();
return 0;
}
#include "header.h"
char func()
{
printf("func is run\n");
return 0;
}
因此我们通常都会把引用操作放在源文件的开头。
避免重复包含
如果不做处理,头文件可能被多次引用,导致大量内容重复而报错。
首先我们有头文件header.h
,其内容如下
struct student
{
int id;
char* name;
};
然后我们有头文件header2.h
,其内容如下
#include "header.h"
然后我们在源文件中对其进行引用
#include <stdio.h>
#include "header.h"
#include "header2.h"
int main()
{
struct student st;
return 0;
}
可以看到,编译器会报struct student
重复定义的错误,因为header.h
被引用了两次。这里我们可以使用如下方式避免
#ifndef HEADER_DEFINE
#define HEADER_DEFINE
源文件内容
#endif
不同的源文件中的HEADER_DEFINE
不同,这个名字可以任意定义,这里运用了上一篇文章的条件编译。当源文件第一次被引用时,由于没有定义HEADER_DEFINE
,条件成立,编译器会定义一个HEADER_DEFINE
宏并处理源文件内容。当源文件第二次被引用时,由于第一次引用已经定义了一个HEADER_DEFINE
,所以条件不成立,下方代码就不会被编译,这样就解决了重复引用的问题。
我们把header.h
改为
#ifndef HEADER_H
#define HEADER_H
struct student
{
int id;
char* name;
};
#endif
把header2.h
改为
#ifndef HEADER_2_H
#define HEADER_2_H
#include "header.h"
#endif
再次编译就能编译通过了,此时源文件的代码就变成了
#include <stdio.h>
#ifndef HEADER_H
#define HEADER_H
struct student
{
int id;
char* name;
};
#endif
#ifndef HEADER_2_H
#define HEADER_2_H
#ifndef HEADER_H
#define HEADER_H
struct student
{
int id;
char* name;
};
#endif
#endif
int main()
{
struct student st;
return 0;
}
首先我们没有定义HEADER_H
条件成立,于是定义了一个HEADER_H
,然后定义了一个结构体struct student
,然后我们没有定义HEADER_2_H
,于是定义了一个HEADER_2_H
,最后由于上方定义了一个HEADER_H
,所以这一行的条件编译不成立,就会直接跳过。