为什么要使用头文件? 把不变的东西封装起来。减少我们的工作量。让代码更简洁,易于维护。 为什么要用 *.h 表示文件,而不用*.c或*.p呢? header,头嘛,所以要用*.h。而且头文件中的变量和函数声明一定不能是定义。多个代码页中有相同的函数或变量定义,那这些代码页就不能链接到一起了。 /* main.c */ #include <stdio.h> #include "stack.h" int main(void) { push('a'); push('b'); push('c'); while(!is_empty()) putchar(pop()); putchar('\n'); return 0; }
为什么#include <stdio.h>
用角括号,而#include "stack.h"
用引号。
对于用角括号包含的头文件,gcc
首先查找-I
选项指定的目录,然后查找系统的头文件目录(通常是/usr/include
,在我的系统上还包括/usr/lib/gcc/i486-linux-gnu/4.3.2/include
);
而对于用引号(一定是双引号啊!)包含的头文件,gcc
首先查找包含头文件的.c
文件所在的目录,然后查找-I
选项指定的目录,然后查找系统的头文件目录。
当然你的头文件可以放到任意位置。然后用 gcc -c main.c -I+目录位置 编译
$ tree . |-- main.c `-- stack |-- stack.c `-- stack.h 1 directory, 3 files然后用用
gcc -c main.c -Istack
编译。
头文件保护(Header Guard):
#ifndef STACK_H #define STACK_H extern void push(char); extern char pop(void); extern int is_empty(void); #endif
这个地方就是一个单例模式,就是保证这段代码在预处理时只拷贝一遍。
重复包含头文件还会有有以下问题:
-
一是使预处理的速度变慢了,要处理很多本来不需要处理的头文件。
-
二是如果有
foo.h
包含bar.h
,bar.h
又包含foo.h
的情况,预处理器就陷入死循环了(其实编译器都会规定一个包含层数的上限)。 -
三是头文件里有些代码不允许重复出现,虽然变量和函数允许多次声明(只要不是多次定义就行),但头文件里有些代码是不允许多次出现的,比如
typedef
类型定义和结构体Tag定义等,在一个程序文件中只允许出现一次。