在程序編譯之前,首先由預(yù)處理器檢查程序。在 GCC 工具鏈中,gcc 和 g++ 分別是C/C++ 編譯程序,而預(yù)處理程序叫 cpp,是獨(dú)立的。根據(jù)程序中使用的預(yù)處理器指令,預(yù)處理器使用符號(hào)縮略語所代表的內(nèi)容替換程序中的縮略語。預(yù)處理指令以 # 為行首,一條指令占據(jù)一行。預(yù)處理器不能理解c/c++,它一般可以接收任何文本并按照替換規(guī)則將其轉(zhuǎn)換成其他文本。
頭文件通過 include 預(yù)處理器指示符(preprocessor include directive) 而成為我們程序的一部分。預(yù)處理器發(fā)現(xiàn) #include 指令后,就會(huì)尋找后跟的文件名并把這個(gè)文件的內(nèi)容包含到當(dāng)前文件中。被包含文件中的文本將替換源代碼文件中的#include 指令, 就像你把被包含文件中的全部內(nèi)容鍵入到源文件中的這個(gè)位置一樣。
#include 指令有兩種使用形式
#include <stdio.h> 文件名放在尖括號(hào)中
#include “mystuff.h” 文件名放在雙引號(hào)中
尖括號(hào) < 和> 括起來表明這個(gè)文件是一個(gè)工程或標(biāo)準(zhǔn)頭文件。查找過程會(huì)檢查預(yù)定義的目錄,我們可以通過設(shè)置搜索路徑環(huán)境變量或命令行選項(xiàng)來修改這些目錄。在 gcc 中可以使用 -I 參數(shù)修改默認(rèn)查找路徑。
如果文件名用一對(duì)引號(hào)括起來則表明該文件是用戶提供的頭文件,查找該
文件時(shí)將從當(dāng)前文件目錄(或文件名指定的其他目錄)中尋找文件,然后再在標(biāo)準(zhǔn)位置尋找文件。
因?yàn)橛?jì)算機(jī)系統(tǒng)的結(jié)構(gòu)不完全相同, 所以ANSI C不要求對(duì)文件采用一樣的目錄模式。一般而言,命名文件的方法依賴于系統(tǒng),但是尖括號(hào)和雙引號(hào)的使用則與系統(tǒng)無關(guān)。
為什么要包含文件呢?
因?yàn)檫@些文件包含了編譯器所需的信息,如函數(shù)的聲明、常量的定義等。例如, 標(biāo)準(zhǔn)庫頭文件stdio.h文件通常包含EOF,NULL,getchar()和putchar()的定義。
包含大型頭文件并不一定顯著增加程序的大小。很多情況下,頭文件中的內(nèi)容是編譯器產(chǎn)生最終代碼所需的信息,而不是加到最終代碼里的具體語句。
被包含的文件還可以含有#include 指示符由于嵌套包含文件的原因一個(gè)頭文件可能會(huì)被多次包含在一個(gè)源文件中條件指示符可防止這種頭文件的重復(fù)處理。
例如:
#ifndef BOOKSTORE_H
#define BOOKSTORE_H
/* Bookstore.h 的內(nèi)容 */
#endif
條件指示符#ifndef 檢查BOOKSTORE_H 在前面是否已經(jīng)被定義,這里BOOKSTORE_H是一個(gè)預(yù)編譯器常量習(xí)慣上預(yù)編譯器常量往往被寫成大寫字母,如BOOKSTORE_H在前面沒有被定義則條件指示符的值為真于是從#ifndef 到#endif 之間的所有語句都被包含進(jìn)來進(jìn)行處理。相反,如果#ifndef 指示符的值為假則它與#endif 指示符之間的行將被忽略,為了保證頭文件只被處理一次,把如下#define 指示符
#define BOOKSTORE_H
放在#ifndef 后面這樣在頭文件的內(nèi)容第一次被處理時(shí)BOOKSTORE_H 將被定義
從而防止了在程序文本文件中以后#ifndef 指示符的值為真。
只要不存在兩個(gè)必須包含的頭文件要檢查一個(gè)同名的預(yù)處理器常量這樣的情形這
個(gè)策略就能夠很好地運(yùn)作。#ifdef 指示符常被用來判斷一個(gè)預(yù)處理器常量是否已被定義以便有條件地包含程序代碼。
#ifdef 除了用于防止重復(fù)包含,還可以用于針對(duì)不同環(huán)境的條件編譯。經(jīng)常出現(xiàn)的有
#if defined (__GCC__) || defined (__SUN_C__)
之類的指令,就是針對(duì)不同編譯器、平臺(tái)進(jìn)行選擇編譯的預(yù)處理指令。當(dāng)編譯環(huán)境沒有定義這個(gè)特定的符號(hào)的時(shí)候,則預(yù)處理器會(huì)自動(dòng)忽略這一部分的代碼。除了用 #ifdef 判斷符號(hào)是否定義,還可以判斷符號(hào)的值。VC 中常見的將 MSC_VER 與特定值比較以判斷 VC 的版本的做法就是這個(gè)道理。
除了以上提到的一些內(nèi)容,還有一些相對(duì)少見的預(yù)處理器指令,如 #pragma。它們分別提供了一些特殊的優(yōu)化手段和編譯器控制方法,可以顯著提高代碼質(zhì)量減輕編碼負(fù)擔(dān),但是很多時(shí)候使用這些編譯指令可能是不兼容于其他編譯環(huán)境的,因此在項(xiàng)目中選用非標(biāo)準(zhǔn)預(yù)處理指令的時(shí)候,應(yīng)該在可移植性和編碼的優(yōu)勢中進(jìn)行衡量后作決定。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)
點(diǎn)擊舉報(bào)。