国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C++ > 正文

C/C++預(yù)處理指令

2019-11-08 03:03:43
字體:
供稿:網(wǎng)友

本文主要記錄了C/C++預(yù)處理指令,常見的預(yù)處理指令如下:

#空指令,無任何效果#include包含一個(gè)源代碼文件#define定義宏#undef取消已定義的宏#if如果給定條件為真,則編譯下面代碼#ifdef如果宏已經(jīng)定義,則編譯下面代碼#ifndef如果宏沒有定義,則編譯下面代碼#elif如果前面的#if給定條件不為真,當(dāng)前條件為真,則編譯下面代碼#endif結(jié)束一個(gè)#if……#else條件編譯塊#error停止編譯并顯示錯(cuò)誤信息

本來只是想了解一下#ifdef,#ifndef,#endif的,沒想到查出來這么多的預(yù)處理指令,上面的多數(shù)都是常見的,但是平時(shí)沒有怎么注意預(yù)處理這方面的內(nèi)容,所以這里梳理一下知識吧。同時(shí)有什么不妥的地方,或者遺漏了什么內(nèi)容,還請留言指出。


什么是預(yù)處理指令?

預(yù)處理指令是以#號開頭的代碼行。#號必須是該行除了任何空白字符外的第一個(gè)字符。#后是指令關(guān)鍵字,在關(guān)鍵字和#號之間允許存在任意個(gè)數(shù)的空白字符。整行語句構(gòu)成了一條預(yù)處理指令,該指令將在編譯器進(jìn)行編譯之前對源代碼做某些轉(zhuǎn)換。

以前沒有在意的學(xué)者注意了,預(yù)處理指令是在編譯器進(jìn)行編譯之前進(jìn)行的操作.預(yù)處理過程掃描源代碼,對其進(jìn)行初步的轉(zhuǎn)換,產(chǎn)生新的源代碼提供給編譯器??梢婎A(yù)處理過程先于編譯器對源代碼進(jìn)行處理。在很多編程語言中,并沒有任何內(nèi)在的機(jī)制來完成如下一些功能:在編譯時(shí)包含其他源文件、定義宏、根據(jù)條件決定編譯時(shí)是否包含某些代碼(防止重復(fù)包含某些文件)。要完成這些工作,就需要使用預(yù)處理程序。盡管在目前絕大多數(shù)編譯器都包含了預(yù)處理程序,但通常認(rèn)為它們是獨(dú)立于編譯器的。預(yù)處理過程讀入源代碼,檢查包含預(yù)處理指令的語句和宏定義,并對源代碼進(jìn)行響應(yīng)的轉(zhuǎn)換。預(yù)處理過程還會刪除程序中的注釋和多余的空白字符。


#include包含一個(gè)源代碼文件

這個(gè)預(yù)處理指令,我想是見得最多的一個(gè),簡單說一下,第一種方法是用尖括號把頭文件括起來。這種格式告訴預(yù)處理程序在編譯器自帶的或外部庫的頭文件中搜索被包含的頭文件。第二種方法是用雙引號把頭文件括起來。這種格式告訴預(yù)處理程序在當(dāng)前被編譯的應(yīng)用程序的源代碼文件中搜索被包含的頭文件,如果找不到,再搜索編譯器自帶的頭文件。采用兩種不同包含格式的理由在于,編譯器是安裝在公共子目錄下的,而被編譯的應(yīng)用程序是在它們自己的私有子目錄下的。一個(gè)應(yīng)用程序既包含編譯器提供的公共頭文件,也包含自定義的私有頭文件。采用兩種不同的包含格式使得編譯器能夠在很多頭文件中區(qū)別出一組公共的頭文件。


#define定義宏

有關(guān)#define這個(gè)宏定義,在C語言中使用的很多,因?yàn)?define存在一些不足,C++強(qiáng)調(diào)使用const來定義常量。宏定義了一個(gè)代表特定內(nèi)容的標(biāo)識符。預(yù)處理過程會把源代碼中出現(xiàn)的宏標(biāo)識符替換成宏定義時(shí)的值。記住僅僅是進(jìn)行標(biāo)識符的替換。下面列舉一些#define的使用:

用#define實(shí)現(xiàn)求最大值和最小值的宏復(fù)制代碼
#include <stdio.h>#define MAX(x,y) (((x)>(y))?(x):(y))#define MIN(x,y) (((x)<(y))?(x):(y))int main(void){#ifdef MAX    //判斷這個(gè)宏是否被定義    PRintf("3 and 5 the max is:%d/n",MAX(3,5));#endif#ifdef MIN    printf("3 and 5 the min is:%d/n",MIN(3,5));#endif    return 0;}/* * (1)三元運(yùn)算符要比if,else效率高 * (2)宏的使用一定要細(xì)心,需要把參數(shù)小心的用括號括起來, * 因?yàn)楹曛皇呛唵蔚奈谋咎鎿Q,不注意,容易引起歧義錯(cuò)誤。*/復(fù)制代碼宏定義的錯(cuò)誤使用復(fù)制代碼
#include <stdio.h>#define SQR(x) (x*x)int main(void){    int b=3;#ifdef SQR//只需要宏名就可以了,不需要參數(shù),有參數(shù)的話會警告    printf("a = %d/n",SQR(b+2));#endif    return 0;}/* *首先說明,這個(gè)宏的定義是錯(cuò)誤的。并沒有實(shí)現(xiàn)程序中的B+2的平方 * 預(yù)處理的時(shí)候,替換成如下的結(jié)果:b+2*b+2 * 正確的宏定義應(yīng)該是:#define SQR(x) ((x)*(x)) * 所以,盡量使用小括號,將參數(shù)括起來。*/復(fù)制代碼宏參數(shù)的連接復(fù)制代碼
#include <stdio.h>#define STR(s) #s#define CONS(a,b) (int)(a##e##b)int main(void){#ifdef STR    printf(STR(VCK));#endif#ifdef CONS    printf("/n%d/n",CONS(2,3));#endif    return 0;}/* (絕大多數(shù)是使用不到這些的,使用到的話,查看手冊就可以了) * 第一個(gè)宏,用#把參數(shù)轉(zhuǎn)化為一個(gè)字符串 * 第二個(gè)宏,用##把2個(gè)宏參數(shù)粘合在一起,及aeb,2e3也就是2000*/復(fù)制代碼用宏得到一個(gè)字的高位或低位的字節(jié)復(fù)制代碼
#include <stdio.h>#define Word_LO(xxx) ((byte)((word)(xxx) & 255))#define WORD_HI(xxx) ((byte)((word)(xxx) >> 8))int main(void){    return 0;}/* * 一個(gè)字2個(gè)字節(jié),獲得低字節(jié)(低8位),與255(0000,0000,1111,1111)按位相與 * 獲得高字節(jié)(高8位),右移8位即可。*/復(fù)制代碼用宏定義得到一個(gè)數(shù)組所含元素的個(gè)數(shù)復(fù)制代碼
#include <stdio.h>#define ARR_SIZE(a) (sizeof((a))/sizeof((a[0])))int main(void){    int array[100];#ifdef ARR_SIZE    printf("array has %d items./n",ARR_SIZE(array));#endif    return 0;}/* *總的大小除以每個(gè)類型的大小 */復(fù)制代碼

關(guān)于#define宏的使用,應(yīng)該特別小心,尤其是含有參數(shù)計(jì)算的時(shí)候如小2示例,最保險(xiǎn)的做法將參數(shù)用括號括起來。


#ifdef,#ifndef,#endif...的使用

以上這些預(yù)編譯指令,都是條件編譯指令,也就是說,將決定那些代碼被編譯,而哪些不被編譯。

示例1:復(fù)制代碼
#include <stdio.h>#include <stdlib.h>#define DEBUGint main(void){    int i = 0;    char c;    while(1)    {        i++;        c = getchar();        if('/n' != c)        {            getchar();        }        if('q' == c || 'Q' == c)        {#ifdef DEBUG//判斷DEBUG是否被定義了            printf("We get:%c,about to exit./n",c);#endif            break;        }        else        {            printf("i = %d",i);#ifdef DEBUG            printf(",we get:%c",c);#endif            printf("/n");        }    }    printf("Hello World!/n");    return 0;}/*#endif用于終止#if預(yù)處理指令。*/復(fù)制代碼ifdef 和 #ifndef復(fù)制代碼
#include <stdio.h>#define DEBUGmain(){#ifdef DEBUG    printf("yes ");#endif#ifndef DEBUG    printf("no ");#endif}//#ifdefined等價(jià)于#ifdef;//#if!defined等價(jià)于#ifndef復(fù)制代碼#else指令

001

#elif指令

002

其他一些指令
#error指令將使編譯器顯示一條錯(cuò)誤信息,然后停止編譯。#line指令可以改變編譯器用來指出警告和錯(cuò)誤信息的文件號和行號。#pragma指令沒有正式的定義。編譯器可以自定義其用途。典型的用法是禁止或允許某些煩人的警告信息。

小結(jié):

預(yù)處理就是在進(jìn)行編譯的第一遍詞法掃描和語法分析之前所作的工作。說白了,就是對源文件進(jìn)行編譯前,先對預(yù)處理部分進(jìn)行處理,然后對處理后的代碼進(jìn)行編譯。這樣做的好處是,經(jīng)過處理后的代碼,將會變的很精短。


參考資料:晚上的影子

 

 

2016年11月12日更新:

寫這篇博文的時(shí)候, 還沒有參加工作. 現(xiàn)在回過頭來, 感覺這篇內(nèi)容寫的還是很晦澀難懂. 因?yàn)楫?dāng)時(shí)的我處于學(xué)生時(shí)代, 對于技術(shù)的理解只有輸入, 沒有過多的工程化的輸出, 導(dǎo)致一些東西理解的還是不夠透徹. 過于這些宏的理解, 目前, 可以簡單的做一下的總結(jié)(宏的基礎(chǔ)知識,往下看即可);

工作中經(jīng)常這樣使用宏:

1. 常常使用宏來調(diào)試代碼:

1234567891011121314151617#if 0///< 舊的代碼(或函數(shù)) (舊的代碼, 將會被預(yù)處理的時(shí)候,屏蔽掉, 不進(jìn)行編譯)#else///< 新的代碼(或函數(shù))#endif #ifndef JOE_DEBUG///< 新的代碼(或函數(shù))#else///< 舊的代碼(或函數(shù)) (舊的代碼, 將會被預(yù)處理的時(shí)候,屏蔽掉, 不進(jìn)行編譯)#endif #ifdef Q_DEBUG///< 新的代碼(或函數(shù))#else///< 舊的代碼(或函數(shù)) (舊的代碼, 將會被預(yù)處理的時(shí)候,屏蔽掉, 不進(jìn)行編譯)#endif<br><br>

  通過以上類似的方法, 可以防止由于過多的修改代碼, 而把代碼修改的一塌糊涂. 建議修改代碼的時(shí)候, 做到保護(hù)好以前的代碼, 盡量不進(jìn)行代碼的刪除操作. 切記, 能不刪除, 就不刪除...不要養(yǎng)成隨手就刪除的習(xí)慣. 要養(yǎng)成使用宏和注釋代碼的習(xí)慣. 

  2. 使用宏來根據(jù)不同的平臺包含不同的文件. 很多時(shí)候, 我們的代碼是需要跨系統(tǒng)平臺編譯和運(yùn)行的. 比如: 一個(gè)小功能代碼, 需要既可以在Win下面運(yùn)行,  還要可以在Max, linux上面運(yùn)行. 可是, 因?yàn)橄到y(tǒng)的不一樣, 有些時(shí)候, 頭文件的包含的名字是不一樣的. 所以,這時(shí)候, 就是用到了宏. 因?yàn)槲覀兪褂镁幊坦ぞ叻植煌南到y(tǒng)平臺, 編程工具自身的環(huán)境就會包含不同平臺的系統(tǒng)宏, 假設(shè)OS_Win, OS_Mac, OS_Linux 分別代碼三種系統(tǒng)不同的宏. 而且,Win版本的編程工具中已經(jīng)定義了OS_Win, 類似的Mac下, 編程工具定義的是OS_Mac, Linux...

12345678910111213#ifdef OS_Win#include <windows.h>#endif #ifdef OS_Mac#include <mac.h>#endif #ifdef OS_Linux#include <linux.h>#endif /** 不僅使用在頭文件的包含. 而且,對于不同的系統(tǒng)平臺. 你也可以使用不同的代碼結(jié)構(gòu). */

   3. 接著就是宏定義了. 使用宏來定義一些常量, 表達(dá)式...詳細(xì)內(nèi)容, 見下面

 


 

2016年12月29日更新:

今天查看以前文件的時(shí)候, 突然發(fā)現(xiàn)了#error 這個(gè)預(yù)處理指令.然后回想一下工作, 發(fā)現(xiàn)這個(gè)指令使用場景還是很多的.比如: 一個(gè)項(xiàng)目的模塊兒之多,源文件之大,代碼之多,那么其中的宏, 也會很多. 免不了沖突定義.這時(shí)候, 我們就需要編譯器能及早的告訴我們.那就是在編譯的時(shí)候.#error就可以這么實(shí)現(xiàn):

/** 如果JOE宏沒有定義,那么編譯就此結(jié)束, 編譯器就會顯示紅色的錯(cuò)誤 */#ifndef JOE#error "JOE is not exits"#endif

 


發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表

圖片精選

主站蜘蛛池模板: 宝鸡市| 绍兴县| 天峻县| 夏津县| 柳州市| 卓资县| 会宁县| 沭阳县| 龙川县| 恩施市| 汤阴县| 获嘉县| 措勤县| 离岛区| 定边县| 临武县| 固镇县| 灵武市| 大连市| 枣阳市| 凤山市| 池州市| 上林县| 宝兴县| 宝坻区| 抚顺县| 新巴尔虎左旗| 武邑县| 襄汾县| 巨野县| 龙川县| 乌兰察布市| 淮南市| 泽普县| 青川县| 耿马| 铁力市| 宁陕县| 镇原县| 正镶白旗| 建德市|