c c 編譯預處理

2021-07-28 11:41:18 字數 4177 閱讀 3116

(1)#include《頭檔名稱》

(2)#include"頭檔名稱"

第一種形式一般用來包含開發環境提供的庫標頭檔案,它指示編譯預處理器

在開發環境中設定的路徑中找所需的標頭檔案。

第二種形式一般用來包含自己寫的標頭檔案,它指示編譯預處理器在當前工

作目錄中搜尋標頭檔案,如果找不到再到開發環境所設定的路徑中找

.#include是乙個偽指令

為了避免同乙個編譯單元包含同 ? 個頭檔案的內容超過一次(這會導致類

型重 復定義錯),我們需要在標頭檔案裡面使用內部包含衛哨。內部包含衛哨實

際上是使用 預處理器的一種標誌巨集。有了內部包含衛哨,我們就可以放心地在

同乙個編譯單元 及其包含的標頭檔案中多次包含同乙個標頭檔案而不會造成重複包

含。例如:

// stddef.h

#ifndef_stddef_h_included_

#define _stddef_h_included_

......

//標頭檔案的內容

#endif

//! stddef h included

// ***.cpp 

#include 「stddef.h」

#include 「stddef.h」 // no problem!

!當包含乙個標頭檔案的時候,如果能始終如一地使用外部包含衛哨,可以顯著地提

高編譯速度,因為當乙個標頭檔案被乙個原始檔反覆包含多次時(常常是因為遞迴的

#include指令展開後所致),可以避免多次查詢和開啟標頭檔案的操作。例如:

#if !definde (_included_stddef_h_)

#include

#define _ included_stddef_h_

#endif //! included_stddef h

建議外部包含衛哨和內部包含衛哨使用同乙個標誌巨集,這樣就可以少定義乙個 | 巨集。例如:

#if ! defined (_stddef_h_included_)

#include 〈stddef.h〉

#endif //!_stddef_h_included_

因為檔案stddefh中的內部包含衛哨就是—stddef_hjncluded—,所以這裡

!不需要再次定義。

可以僅在標頭檔案中包含其他標頭檔案時使用外部包含衛哨,原始檔中可以不使用,

也基本不會影響編譯速度。

巨集不可以除錯,因為巨集不會進入符號表(符號表是編譯器建立的,在編譯 時巨集已經消失了),即使巨集替換後出現了語法錯誤,編譯器也會將錯誤定位到源程式 中而不是定位到具體的某個巨集定義中。

合併操作符##將出現在其左右的字串行合併成乙個新的識別符號(注意,不 |是字串)。例如:

#define class_name(name) class##name 

#define mhrge(x, y) x##y##x

則巨集引用:

class_name(systimer)

merge(me, to)

將分別擴充套件為如下兩個識別符號:

classsystimer 

metome

使用合併操作符##時,產生的識別符號必須預先有定義,否則編譯器會報「識別符號未定義」的編譯錯誤。

編譯偽指令#pragma用於執行語言實現所定義的動作(見示例9 - 5), 具體參考你 i所使用的編譯器的幫助文件。

示例9 - 5

#pragma pack(push, 8)	/*物件成員對齊位元組數*/

#pragma pack(pop)

#pragma waming(disable:4069) /* 不要產生第 c4069 號編譯警告 */

#pragma comment(lib, "kemel32.1ib」)

#pragma comment(lib, "user32.1ib")

#pragma comment(lib, "gdi32.1ib")

(1)雖然巨集定義很靈活,並且通過彼此結合可以產生許多變形用法,但 是c++/c程式設計師不要定義很複雜的巨集,巨集定義應該簡單而清晰;

(2)巨集名採用大寫字元組成的單詞或其縮寫序列,並在各單詞之間使用分隔;

(3)如果需要公布某個巨集,那麼該巨集定義應當放置在標頭檔案中,否則放 置在實現檔案(.cpp)的頂部;

(4)不要使用巨集來定義新型別名,應該使用typedef,否則容易造成錯誤。

(5)給巨集新增注釋時請使用塊注釋(/*

*/),而不要使用行注釋。因為有些編譯器可能會把巨集後面的行注釋理解為巨集體的一部分;

(6)盡量使用const取代巨集來定義符號常量;

(7)對於較長的使用頻率較髙的重複**片段,建議使用函式或模板而不要使用帶引數的巨集定義;而對於較短的重複**片段,可以使用帶參 數的巨集定義,這不僅是出於型別安全的考慮,而且也是優化與折衷的體現;

(8)盡量避免在區域性範圍內(如函式內、型別定義內等)定義巨集,除非它只在該區域性範圍內使用,否則會損害程式的清晰性。

使用條件編譯可以控制預處理器選擇不同的**段作為編譯器的輸入,從而使 !得源程式在不同的編譯條件下產生不同的目標**。條件編譯偽指令就如同程式控 !制結構中的選擇結構,不同的是前者只在編譯預處理階段即在正式編譯之前發揮作 丨用(不生成執行時**),而後者則是在執行時起作用的。條件編譯為程式的移植和 !除錯帶來了極大的方便,可以用它來暫時或永久性地阻止一段**的編譯。我們將 在下面看到它的價值。條件編譯偽指令主要包括#if、#ifdef. #ifhdef、#elif、#else、

丨#endif、defined。每乙個條件編譯塊都必須以#if開始,##endif結束,#if必須與它 丨下面的某一#endif配對;defined必須結合甜丨或#6證使用,而不能單獨使用。條件 i編譯塊可以出現在程式**的任何地方。

在程式設計過程中,當需要暫時放棄編譯一段**的時候,我們習慣於使用塊注釋 來把它遮蔽掉。但是如果這段**本身就含有塊注釋時,那麼雙重注釋很麻煩。此時我們可以使用條件編譯偽指令#if來遮蔽這段**,如下**所示。如果要使這段**生效,只需把0改為任何乙個非0的值(例如1)即可。但是千萬要記住:不要企圖用#if來代替塊注釋,兩者根本不是同一種用途。

#if 0

... /*...*/ //希望禁止編譯的**段

... /*...*/ //希望禁止編譯的**段

#endif

由於條件編譯由編譯預處理器來處理,顯然預編譯偽指令無法計算有變數參與其中的表示式或sizeof表示式,因此只能用常量表示式。如果常量表示式的值非0, 則條件為真:否則條件為假(見示例9-2)。

示例9-2

#define flag_dos 2 

#defme flag_unix 1

#define flag_win 0

#define os 1

#if os == flag_dos

cout<

預編譯偽指令#ifdefxyz等價於#ifdefmed(xyz),此處xyz稱為除錯巨集。如果 前面曾經用#defme定義過巨集xyz,那麼#ifdefxyz表示條件為真,否則條件為假。 例如:

#define xyz

。。。

#ifdef xyz 

dosomethingo;

#endif

如果你不想讓dosomething();語句被編譯,那麼刪除#define xyz,或者在其後 用#undef xyz取消該巨集即可。 預編譯偽指令#ifhdef xyz等價於#if !defmed(xyz)。示例9-3演示了內部包含衛

哨的用法。

示例9-3

#ifndef graphics_h //防止graphics.h被重複引用

#define graphics_h

#include "myheader.h"//引用非標準庫的標頭檔案

#include //引用標準庫的標頭檔案

...//一些函式的定義和宣告

#endif

C C 編譯預處理

今天做練習用到頭檔案包含時遇到了 redefinition 的報錯。仔細一看才發現是 我沒有很好地使用條件編譯來協調標頭檔案包含關係 平常說的 標頭檔案衛士 就這麼回事 於是找來塵封已久的 c預處理程式 在用c編譯程式對c源 進行編譯之前,即在語法分析 生成和優化之前,由c 預處理程式對源 進行第一...

C C 編譯預處理

1.c c 編譯預處理 預處理 或稱預編譯 是指在進行編譯的第一遍掃瞄 詞法掃瞄和語法分析 之前所作的工作。預處理指令指示在程式正式編譯前就由編譯器進行的操作,可放在程式中任何位置。預處理是 c語言的乙個重要功能,它由預處理程式負責完成。當對乙個原始檔進行編譯時,系統將自動引用預處理程式對源程式中的...

C C 編譯預處理指令

眾所周知,你的程式編譯前要做的事就是掃瞄源 對其做初步的轉換,產生新的源 提供給編譯器,這個過程就叫編譯預處理。這個處理過程由預處理器來完成,預處理器是在程式真正執行前由編譯器呼叫的預處理程式。常見的預處理有以下三種 include 是一種最為常見的預處理,主要是做為檔案的引用組合源程式正文。巨集替...