CPP Info Memo part 2
Table of Contents
1 Overview
2 Header Files
C 里面有很多声明和宏定义是专门用来在多个源文件(source file)中共享的, 这些东西被放在专门的文件中,即传说中的头文件(Header file)。 我们可以通过 #include 来通知 preprocessor 来把他们 include 进来。
include 一个头文件,实际上和把这个头文件的内容拷贝进源文件是等效的。 但拷贝操作耗时,且一旦一个头文件稍作修改,所有源文件都要随之变化。 而 include 则解决了这个问题。
2.1 Include 语法
include 有两个用法,即
#include <FILE> #include "FILE"
区别在于:
-
#include <FILE>
该用法用于 include 系统提供的头文件。 它从标准的系统搜索路径中去寻找指定的头文件。 GCC 中,我们可以通过 -I 来将某个目录添加到搜索路径中去。
-
#Include "FILE"
该用法用来 include 用户自己的头文件。 它先从当前路径下搜索,随后去所谓的引用目录(quoted directory)去找, 最后去系统的标准搜索路径中去找。 引用目录可以通过 -iquote 选项来指定。
无论哪种形式,include 后面的参数在预编译的时候都会被当作字符串常量一样来看待。 其中的*/、/* 不会被当成注释,其中的宏也不会被展开,连 "\" 也不会被看作是转义字符。
2.2 Include 操作
2.2.1 头文件的展开
如果一个源文件中包涵了 include 指令, include 指令会让 preprocessor 扫描指定的头文件, 并将源文件其他的内容添加到扫描的输出后面。
例如下面的这个例子:
// Contents in header.h char *test (void); // Contents in test.c int x; #include "header.h" int main (void) { puts (test ()); }
上面代码中有两个文件: header.h 和 test.c , 则经过预编译后,会变成:
int x; char *test (void); int main (void) { puts (test ()); }
2.2.2 Files that can be included
可以被用来作为 include 的参数的,不只是头文件, 任何包含了 C 程序的片段的文件都可以——只要被包含的文件包含有完整的 tokens 。
因此,Teacher Tan 在他的书中教给学生去 include 一个源文件,也没什么错, 只是这么做不值得推荐而已。 被包含的头文件中,最好是仅有完整的语法单元: 函数声明或者定义、类型声明等等。
2.3 搜索路径
2.3.1 默认路径
GCC 会在多个不同的目录下搜索头文件,例如我的机器上用 CEDET 查到的编译 C++ 时候的搜索路径如下:
(semantic-gcc-get-include-paths "c++") ("/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/include/g++-v4" "/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/include/g++-v4/x86_64-pc-linux-gnu" "/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/include/g++-v4/backward" "/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/include" "/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/include-fixed" "/usr/include")
2.3.2 路径的修改
我们可以通过选项来修改搜索路径:
-
"-I"
该选项用来向这个路径中添加搜索路径,自行添加的路径将会被放到搜索路径的最前端。
-
"-nostdinc"
该选项用于禁止 GCC 去默认搜索路径中搜索文件,例如编译内核时会用到该选项, Linux 内核中相关的部分 Makefile 如下:
NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include) CHECKFLAGS += $(NOSTDINC_FLAGS)
但是,通过 "-I" 选项向其中添加的路径不会被禁止。
-
"-iquote"
该选项用于在使用
#inclde "FILE"
这种形式时候添加搜索路径。