摘要:在C/C++語言編程過程中,經(jīng)常會用到如#include、#define等指令,同時也會涉及到大量的預(yù)處理與條件編譯,這樣做的好處可以使代碼更利于移植移植性,也讓代碼易于修改。 因此引入了預(yù)處理與條件編譯的概念。
預(yù)處理的行為是由指令控制的。 所有的預(yù)處理器命令都是以#開頭,它必須是第一個非空字符。 預(yù)處理指令由預(yù)處理程序(預(yù)處理器)操作。
預(yù)處理器不是編譯器的組成部分,但是它是編譯過程中一個單獨的步驟。 因此, 預(yù)處理器只不過是一個文本替換工具而已,它們會指示編譯器在實際編譯之前完成所需的預(yù)處理。 通俗來講預(yù)處理命令的作用就是在編譯和鏈接之前,對源文件進行一些文本方面的操作,比如文本替換、文件包含、刪除部分代碼等,這個過程叫做預(yù)處理(在編譯之前對源文件進行簡單加工)
相比其他編程語言,C/C++語言更依賴預(yù)處理器,故在閱讀或開發(fā)C/C++程序過程中,可能會接觸大量的預(yù)處理指令。 預(yù)處理指令不屬于C/C++語言的語法,但在一定意義上可以說預(yù)處理擴展了C/C++。 預(yù)處理命令的分類主要劃分為以下幾種類型:
1、宏定義
#define命令并不是真正的定義符號常量,而是定義一個可以替換的宏。 被定義為宏的標示符稱為“宏名”。 在編譯預(yù)處理過程時,對程序中所有出現(xiàn)的“宏名”,都用宏定義中的字符串去代換,這稱為“宏代換”或“宏展開”。 宏替換在編譯前進行,不分配內(nèi)存; 宏展開不占運行時間,只占編譯時間; 宏替換只作替換,不做計算。
#define NEMBER 9 //#define 宏名 文本
#define M(a, b) a*b //#define 宏名(參數(shù)表) 文本
#define SWITCHON //#define 宏名 //(定義一個條件編譯的開關(guān)字段)
#define NAME(n) num ## n //宏定義,使用 ## 運算符,粘合的作用
int num0 = 10;
printf("num0 = %d\\n", NAME(0));//宏調(diào)用NAME(0)被替換為 num ## 0,被粘合為:num0。
//可變宏:… 和 __VA_ARGS__
#define PR(...) printf(__VA_ARGS__) //宏定義
PR("hello\\n"); //宏調(diào)用
//輸出結(jié)果:hello
//在宏定義中,形參列表的最后一個參數(shù)為省略號“…”,而“__VA_ARGS__”就可以被用在替換文本中,來表示省略號“…”代表了什么。
//而上面例子宏代換之后為:printf(“hello\\n”);
#undef指令刪除前面定義的宏名字(也就是#define的標識符)。 也就是說,它“不定義”宏。 (注意:如果標識符當前沒有被定義成一個宏名稱,那么就會忽略該指令),一般形式為:
#undef NEMBER //取消之前已定義的NEMBER
#define NEMBER 100 //重新定義NUMBE為100
2、系統(tǒng)預(yù)定義的宏
LINE : 當前源文件的行號,整數(shù)
FILE : 當前源文件名,char 字符串,文件的完整路徑和文件名**
DATE : 當前編譯日期,char 字符串,格式:月 日 年
TIME : 當前編譯時間,char 字符串,格式:時 分 秒
STDC : 整數(shù) 1,表示兼容 ANSI/ISO C 標準,配合 #if 使用
**TIMESTAMP ** : 最后一次修改當前文件的時間戳,char 字符串,格式:年 月份 日期 時 分 秒
3、文件包含
當一個C語言程序由多個文件模塊組成時,主模塊中一般包含main函數(shù)和一些當前程序?qū)S玫暮瘮?shù)。 程序從main函數(shù)開始執(zhí)行,在執(zhí)行過程中,可調(diào)用當前文件中的函數(shù),也可調(diào)用其他文件模塊中的函數(shù)。
如果在模塊中要調(diào)用其他文件模塊中的函數(shù),首先必須在主模塊中聲明該函數(shù)原型。 一般都是采用文件包含的方法,包含其他文件模塊的頭文件。
包含文件的格式有#include后面跟尖括號<>和雙引號“”之分。 兩者的主要差別是搜索路徑的不同。 C的標準庫加.h,C++標準庫可以不加.h。
尖括號形式:如#include
雙引號形式:如#include“para.h”,首先到當前工作目錄下查找該文件,如果未發(fā)現(xiàn),再按尖括號包含時的辦法到系統(tǒng)目錄下查找。 包含自定義的頭文件,一般采用該方式。 雖然系統(tǒng)標準庫頭文件采用此方式也正確,但浪費了不必要的搜索時間,故系統(tǒng)標準庫頭文件不建議采用該包含方式。
4、條件編譯
條件編譯允許程序員有選擇按照不同的條件去編譯程序的不同部分,從而得到不同的目標代碼。 使用條件編譯,可方便地處理程序的調(diào)試版本和正式版本,也可使用條件編譯使程序的移植更方便。
常見的條件編譯指令有 #if、#elif、#else、#endif、#ifdef、#ifndef。
#if、#elif、#else、#endif的使用和if、elseif 、else的使用非常相似,一般使用格式如下:
#if 整型常量表達式1
程序段1
#elif 整型常量表達式2
程序段2
#else
程序段3
#endif
執(zhí)行起來就是,如果整形常量表達式為真,則執(zhí)行程序段1,否則繼續(xù)往后判斷依次類推(注意是整形常量表達式),最后#endif是#if的結(jié)束標志。
#ifdef的作用是判斷某個宏是否定義,如果該宏已經(jīng)定義則執(zhí)行后面的代碼,#ifndef恰好和#ifdef相反,一般使用格式如下:
//ifdef
#ifdef 宏名
程序段1
#else
程序段2
#endif
//ifndef
#ifndef 宏名
程序段1
#else
程序段2
#endif
#ifdef表示如果該宏已被定義過,則對“程序段1”進行編譯,否則對“程序段2”進行編譯(這個和上面的#if一樣最后都需要#endif),上述格式也可以不用#else,這一點上和if else相同。
#ifndef表示如果該宏未被定義,則對“程序段1”進行編譯,否則對“程序段2”進行編譯。
5、特殊命令
#line 可以改變 LINE 和 _FILE_兩個宏的內(nèi)容,即為其指定新的值。 其本質(zhì)是重定義 LINE 和 FILE ,主要有以下兩種形式:
#line linenum
#line linenum 文件名
int main()
{
printf( "code is on line %d, in file %s\\n", __LINE__, __FILE__ );
#line 10
printf( "code is on line %d, in file %s\\n", __LINE__, __FILE__ );
#line 20 "hello.cpp"
printf( "code is on line %d, in file %s\\n", __LINE__, __FILE__ );
printf( "code is on line %d, in file %s\\n", __LINE__, __FILE__ );
}
輸出為:
code is on line 7, in file line_directive.cpp
code is on line 10, in file line_directive.cpp
code is on line 20, in file hello.cpp
code is on line 21, in file hello.cpp
#error :當預(yù)處理器預(yù)處理到#error命令時將停止編譯并輸出用戶自定義的錯誤消息,一般用于調(diào)試程序。
#error [用戶自定義的錯誤消息]
//注:上述語法成份中的方括號"[]"代表用戶自定義的錯誤消息可以省略不寫。
//舉例1:
#error Sorry,an error has occurred!
//舉例2:
#error
#ifndef A
#define A 5
#endif
#if A < 5
#error Sorry,an error has occurred!
#endif
#warning :****類似于#error 指令,但不會導(dǎo)致取消預(yù)處理,程序繼續(xù)編譯,不會影響程序的正常運行。 #warning 指令之后的信息在預(yù)處理繼續(xù)之前作為消息輸出,產(chǎn)生警告。
#warning [用戶自定義的警告信息]
#warning Sorry,an warning has occurred!
#pragma:是功能比較豐富且靈活的指令,可以有不同的參數(shù)選擇,從而完成相應(yīng)的特 定功能操作。 #pragma指令是計算機或操作系統(tǒng)特定的,并且通常對于每個編譯器而言都有所不同。 #pragma指令可用于條件語句以提供新的預(yù)處理器功能,或為編譯器提供實現(xiàn)所定義的信息
其格式一般為: #pragma Para。 其中Para 為參數(shù),參數(shù)可以有 message 類型、code_seg、once、warning、pack 等,具體可以在網(wǎng)上詳細查看。 舉兩個常用的例子:
#pragma一次
只要在頭文件的最開始加入這條指令就能夠保證指定該文件在編譯源代碼文件時僅由編譯器包含(打開)一次,使用 #pragma once 可減少生成次數(shù),和使用預(yù)處理宏定義來避免多次包含文件的內(nèi)容的效果是一樣的,但是需要鍵入的代碼少,可減少錯誤率,這條指令實際上在VC6中就已經(jīng)有了,但是考慮到兼容性并沒有太多的使用它。
//使用#progma once
#pragma once
// Code placed here is included only once per translation unit
//使用宏定義方式
#ifndef HEADER_H_
#define HEADER_H_
// Code placed here is included only once per translation unit
#endif // HEADER_H_
#pragma once是編譯相關(guān),就是說這個編譯系統(tǒng)上能用,但在其他編譯系統(tǒng)不一定可以,也就是說移植性差,不過基本上已經(jīng)是每個編譯器都有這個定義了。
#pragma包 (n)
指定結(jié)構(gòu)、聯(lián)合和類成員的封裝對齊。 其實就是改變編譯器的內(nèi)存對齊方式。 這個功能對于集合數(shù)據(jù)體使用,默認的數(shù)據(jù)的對齊方式占用內(nèi)存比較大,可進行修改。 在沒有參數(shù)的情況下調(diào)用pack會將n設(shè)置為編譯器選項中設(shè)置的值。 如果未設(shè)置編譯器選項,windows默認為8,linux默認為4。 具體的使用方法為,其中n稱為對齊系數(shù),取值必須是2的冪次方,即1、2、4、8、16等。
1. #pragma pack(show) 以警告信息的形式顯示當前字節(jié)對齊的值.
2. #pragma pack(n) 將當前字節(jié)對齊值設(shè)為 n .
3. #pragma pack() 將當前字節(jié)對齊值設(shè)為默認值(通常是8) .
4. #pragma pack(push) 將當前字節(jié)對齊值壓入編譯棧棧頂.
5. #pragma pack(pop) 將編譯棧棧頂?shù)淖止?jié)對齊值彈出并設(shè)為當前值.
6. #pragma pack(push, n) 先將當前字節(jié)對齊值壓入編譯棧棧頂, 然后再將 n 設(shè)為當前值.
7. #pragma pack(pop, n) 將編譯棧棧頂?shù)淖止?jié)對齊值彈出, 然后丟棄, 再將 n 設(shè)為當前值.
8. #pragma pack(push, identifier) 將當前字節(jié)對齊值壓入編譯棧棧頂, 然后將棧中保存該值的位置標識為 identifier .
10. #pragma pack(pop, identifier) 將編譯棧棧中標識為 identifier 位置的值彈出, 并將其設(shè)為當前值. 注意, 如果棧中所標識的位置之上還有值, 那會先被彈出并丟棄.
11. #pragma pack(push, identifier, n) 將當前字節(jié)對齊值壓入編譯棧棧頂, 然后將棧中保存該值的位置標識為 identifier, 再將 n 設(shè)為當前值.
12. #pragma pack(pop, identifier, n) 將編譯棧棧中標識為 identifier 位置的值彈出, 然后丟棄, 再將 n 設(shè)為當前值. 注意, 如果棧中所標識的位置之上還有值, 那會先被彈出并丟棄.
//注意: 如果在棧中沒有找到 pop 中的標識符, 則編譯器忽略該指令, 而且不會彈出任何值.
通常成對使用:
#pragma pack (n) //作用:編譯器將按照n個字節(jié)對齊。
#pragma pack () //作用:取消自定義字節(jié)對齊方式。
#pragma pack (push,1) //作用:是指把原來對齊方式設(shè)置壓棧,并設(shè)新的對齊方式設(shè)置為一個字節(jié)對齊
#pragma pack(pop) //作用:恢復(fù)對齊狀態(tài)
-
處理器
+關(guān)注
關(guān)注
68文章
19286瀏覽量
229865 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4331瀏覽量
62629 -
命令
+關(guān)注
關(guān)注
5文章
684瀏覽量
22027 -
C++
+關(guān)注
關(guān)注
22文章
2108瀏覽量
73657 -
編譯器
+關(guān)注
關(guān)注
1文章
1634瀏覽量
49134
發(fā)布評論請先 登錄
相關(guān)推薦
評論