一預處理
1.常見的預處理功能
文件包含:#include 是一種最為常見的預處理,主要是做為文件的引用組合源程序正文。
條件編譯:#if,#ifndef,#ifdef,#endif,#undef等也是比較常見的預處理,主要是進行編譯時進行有選擇的挑選,注釋掉一些指定的代碼,以達到版本控制、防止對文件重復包含的功能。
布局控制:#pragma,這也是我們應用預處理的一個重要方面,主要功能是為編譯程序提供非常規的控制流信息。
宏替換:#define,這是最常見的用法,它可以定義符號常量、函數功能、重新命名、字符串的拼接等各種功能。
2.常見的預處理指令:
#define 宏定義#undef 未定義宏
#include 文本包含
#ifdef 如果宏被定義就進行編譯
#ifndef 如果宏未被定義就進行編譯
#endif 結束編譯塊的控制
#if 表達式非零就對代碼進行編譯
#else 作為其他預處理的剩余選項進行編譯
#elif 這是一種#else和#if的組合選項 //后面有例子的
#line 改變當前的行數和文件名稱
#error 輸出一個錯誤信息
#pragma 為編譯程序提供非常規的控制流信息
3.預處理標識符
為了處理一些有用的信息,預處理定義了一些預處理標識符,雖然各種編譯器的預處理標識符不盡相同,但是他們都會處理下面的4種:__FILE__ 正在編譯的文件的名字
__LINE__ 正在編譯的文件的行號
__DATE__ 編譯時刻的日期字符串,例如: "25 Jan 2006"
__TIME__ 編譯時刻的時間字符串,例如: "12:30:55"
例如:
cout<<"The file is :"<<__FILE__"<<"! The lines is:"<<__LINE__<<endl;
二、頭文件保護符
1.條件編譯
頭文件應該含有保護符,即使這些頭文件不會被其他頭文件包含。編寫頭文件保護符並不困難,而且如果頭文件被包含多次,它可以避免難以理解的編譯錯誤。
利用宏定義和條件編譯#ifndef指示檢測指定的預處理變量是否未定義。如果預處理器變量未定義,那么跟在后面的所有指示都被處理,直到出現#endif。
可以使用這些措施來預防多次包含同一頭文件:
/*** 頭文件salesitem.h ***/ #ifndef SASESITEM_H #define SALESITEM_H //...這里是內容 #endif
條件指示#ifndef SALESITEM_H測試 SALESITEM_H 預處理器變量是否未定義。如果 SALESITEM_H 未定義,那么 #ifndef 測試成功,跟在 #ifndef 后面的所有行都被執行,直到發現#endif。相反,如果 SALESITEM_H 已定義,那么 #ifndef 指示測試為假,該指示和 #endif 指示間的代碼都被忽略。
為了保證頭文件在給定的源文件中只處理過一次,我們首先檢測 #ifndef。第一次處理頭文件時,測試會成功,因為 SALESITEM_H 還未定義。下一條語句定義了 SALESITEM_H。那樣的話,如果我們編譯的文件恰好又一次包含了該頭文件。#ifndef 指示會發現 SALESITEM_H 已經定義,並且忽略該頭文件的剩余部分。
當沒有兩個頭文件定義和使用同名的預處理器常量時,這個策略相當有效。我們可以為定義在頭文件里的實體(如類)命名預處理器變量來避免預處理器變量重名的問題。一個程序只能含有一個名為 Sales_item 的類。通過使用類名來組成頭文件和預處理器變量的名字,可以使得很可能只有一個文件將會使用該預處理器變量。
頭文件保護方式二 --------------------------------------------------------------------------------------
#pragma once
這是一個比較常用的指令,只要在頭文件的最開始加入這條指令就能夠保證頭文件被編譯一次
#pragma once用來防止某個頭文件被多次include,#ifndef,#define,#endif用來防止某個宏被多次定義。
#pragma once是編譯相關,就是說這個編譯系統上能用,但在其他編譯系統不一定可以,也就是說移植性差,不過現在基本上已經是每個編譯器都有這個定義了。
#ifndef,#define,#endif這個是C++語言相關,這是C++語言中的宏定義,通過宏定義避免文件多次編譯。所以在所有支持C++語言的編譯器上都是有效的,如果寫的程序要跨平台,最好使用這種方式
三、比較
#pragma once與 #ifndef的區別
為了避免同一個文件被include多次
1 #ifndef方式
2 #pragma once方式
在能夠支持這兩種方式的編譯器上,二者並沒有太大的區別,但是兩者仍然還是有一些細微的區別。
方式一:
#ifndef __SOMEFILE_H__ #define __SOMEFILE_H__ ... ... // 一些聲明語句 #endif
方式二:
#pragma once ... ... // 一些聲明語句
#ifndef的方式依賴於宏名字不能沖突,這不光可以保證同一個文件不會被包含多次,也能保證內容完全相同的兩個文件不會被不小心同時包含。當然,缺點就是如果不同頭文件的宏名不小心“撞車”,可能就會導致頭文件明明存在,編譯器卻硬說找不到聲明的狀況
#pragma once則由編譯器提供保證:同一個文件不會被包含多次。注意這里所說的“同一個文件”是指物理上的一個文件,而不是指內容相同的兩個文件。帶來的好處是,你不必再費勁想個宏名了,當然也就不會出現宏名碰撞引發的奇怪問題。對應的缺點就是如果某個頭文件有多份拷貝,本方法不能保證他們不被重復包含。當然,相比宏名碰撞引發的“找不到聲明”的問題,重復包含更容易被發現並修正。
方式一由語言支持所以移植性好,方式二可以避免名字沖突