gcc:預先處理語句--#include和#include_next

來源:互聯網
上載者:User

       原創文章,轉載請註明出處,謝謝!       
       作者:清林,部落格名:飛空靜渡

 

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

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.