gcc:预处理语句--#include和#include_next

来源:互联网 发布:笨方法学python下载 编辑:程序博客网 时间:2024/06/05 03:14

       原创文章,转载请注明出处,谢谢!       
       作者:清林,博客名:飞空静渡

 

#include


如果从纯粹的text文件来说,#include的作用就是搜索它后面指示的文件,并把这个文件的内容加到当前的文件中。一般我们编程时,都是包含一些与.h为后缀的头文件,但是它可以包含任何后缀的任何形式的text文件的,而不仅仅是.h为后缀的头文件。

#include有两种形式,例如如下:

#include <syshead.h>
#include "userhead.h"
用尖括号表示的是包含系统的头文件,用双引号包含的是用户自己的头文件。

 

下面是使用#include时的一些规则:

1)使用<>包含的头文件一般会先搜索-I选项后的路径(即用gcc编译时的-I选项),之后就是标准的系统头文件路径。

2)而用""号包含的头文件会首先搜索当前的工作目录,之后的搜索路径才是和<>号包含的头文件所搜索的路径一样的路径。

3)在unix系统中,一般标准的头文件路径为:

/usr/local/include
/usr/lib/gcc-lib/target/version/include
/usr/target/include
/usr/include
4)一般有两条独立的头文件搜索路径链。一条是-I后面指示的路径,另一条是系统头文件路径和以-prefix, -withprefix,和-idirafter后操作的目录。

5)如果gcc编译的是c++的程序,那么在搜索上面所说的目录前,预处理器会首先搜索/usr/include/g++v3目录,v3是你的gcc中c++的版本。

6)在头文件中运行增加路径名,例如:#include <sys/time.h>,那么就会在搜索的系统目录的sys目录下寻找time.h文件。

7)一般会用斜线来作为目录的分割符,甚至有些系统使用不同的字符作为分割符(例如反斜线)。

8)#include后面所包含的文件名就是文件名,例如abc*d.h这个文件,必须就要有abc*d.h这个文件,而不是abckkkd.h这些文件,*不能解释成任  

    何的字符的意思,而是实实在在的一个字符。

9)可以使用一个指定的名字作为#include指令后面的头文件,例如:

#define BOGHEADER "bog_3.h"
#include BOGHEADER
10)在#include 指令的后面,除了所包含的头文件和注释外,不能包含其它的任何东西了。

11)#line指令不能改变当前的工作目录。

12)-I-选项可以改变-I指定的搜索目录。


#include_next

 

#include_next是GNU的一个扩展,并不是标准C中的指令。

#include_next看起来有些复杂,但在这里我将详详细细的说明一下,希望可以把它讲的清楚,让读者了解 :)

 

首先,我将会说明一下这条指令的功能,然后说明一下为什么要引人这条指令,希望能说个明白。

#include_next和#include指令一样,也是包含一个头文件,它们的不同地方是包含的路径不一样。

#include_next的意思就是“包含指定的这个文件所在的路径的后面路径的那个文件”,听起来是不是很坳口,我自己也觉得是这样,但下面举个例子说明就清楚了。

例如有个搜索路径链,在#include中,它们的搜索顺序依次是A,B,C,D和E。在B目录中有个头文件叫a.h,在D目录中也有个头文件叫a.h,如果在我们的源代码中这样写#include <a.h>,那么我们就会包含的是B目录中的a.h头文件,如果我们这样写#include_next <a.h>那么我们就会包含的是D目录中的a.h头文件。#include_next <a.h>的意思按我们上面的引号包含中的解释来说就是“在B目录中的a.h头文件后面的目录路径(即C,D和E)中搜索a.h头文件并包含进来)。#include_next <a.h>的操作会是这样的,它将在A,B,C,D和E目录中依次搜索a.h头文件,那么首先它会在B目录中搜索到a.h头文件,那它就会以B目录作为分割点,搜索B目录后面的目录(C,D和E),然后在这后面的目录中搜索a.h头文件,并把在这之后搜索到的a.h头文件包含进来。这样说的话大家应该清楚了吧。

 

还有一点是#include_next是不区分<>和""的包含形式的。

 

现在来说说为什么要引人这条指令!

假如,你要创建一个新的头文件,而这个新的头文件和现在已有的头文件有相同的名字,而且你想用你的这个新的头文件,那么你要做的就是把这个新的头文件放在#include指令的搜索路径的前面,即是在旧的头文件的前面新的头文件首先被搜索到,这样你就可以使用你这个新的头文件。但是你在另一个源代码文件中想使用旧的头文件了,那怎么办!有个办法就是使用绝对路径来搜索,那么就不存在这样的问题了。问题出在,如果我们把头文件的位置移动了,移到了其它的目录里了,那我们就得在相应的源码文件中修改这个包含的绝对路径,如果一个源码文件还好,但如果是大型工程的话,修改的地方多了就容易出问题。

又进一步说,如果你这个新的头文件引用了旧的头文件,而这个新的头文件如果没有使用只编译一次的预处理语句包含(即#ifndef,#endif等),那么就会陷入一个无限的递归包含中,这个新的头文件就会无限的包含自己,就会出现一个致命的错误。如果我们使用#include_next就会避免这样的问题。

在标准的C中,这没有一个办法来解决上面的问题的,因此GNU就引人了这个指令#include_next。

 

下面再举一个#include_next的例子。

假设你用-I选项指定了一个编译包含的路径 '-I /usr/local/include',这个路径下面有个signal.h的头文件,在系统的'/usr/include'下也有个signal.h头文件,我们知道-I选项的路径首先搜索。如果我们这样#include <signal.h>包含,就会包含进/usr/local/include下的signal.h头文件;如果是#include_next <signal.h>,就会包含'/usr/include'下的signal.h头文件。

GNU建议一般没有其它可取代的办法的情况下才使用#include_next的。

 

又一个例子,如在系统头文件stdio.h中,里面有个函数(应该说是一个宏)getc,它从标准输入中读取一个字符。你想重新定义一个getc,并放到自己新建的stdio.h文件中,那么你可以这样使用你自定义的getc。

#include_next "stdio.h"
#undef getc
#define getc(fp) ((int)'x')

 

更多的说明请参考GNU的官方文档和GCC文档。

 

原创粉丝点击