天天看點

預處理語句--#include和#include_next

#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文檔。

轉載自http://blog.csdn.net/fjb2080/article/details/5247494

繼續閱讀