C++預處理和頭文件保護符


一預處理

1.常見的預處理功能

預處理器的主要作用就是把通過預處理的內建功能對一個資源進行等價替換,最常見的預處理有:文件包含,條件編譯、布局控制和宏替換4種。
文件包含:#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.條件編譯

[html]  view plain copy
#ifdef XXX   //或者 #ifndef  
//
(#else)  
//
#endif  

例如: 

#ifdef WINDOWS   
//....   
//....   
#endif   
#ifdef LINUX   
//....   
//....   
#endif 

2.編寫頭文件保護符

 頭文件應該含有保護符,即使這些頭文件不會被其他頭文件包含。編寫頭文件保護符並不困難,而且如果頭文件被包含多次,它可以避免難以理解的編譯錯誤。

利用宏定義和條件編譯#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則由編譯器提供保證:同一個文件不會被包含多次。注意這里所說的“同一個文件”是指物理上的一個文件,而不是指內容相同的兩個文件。帶來的好處是,你不必再費勁想個宏名了,當然也就不會出現宏名碰撞引發的奇怪問題。對應的缺點就是如果某個頭文件有多份拷貝,本方法不能保證他們不被重復包含。當然,相比宏名碰撞引發的“找不到聲明”的問題,重復包含更容易被發現並修正。

方式一由語言支持所以移植性好,方式二可以避免名字沖突


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM