現代C 中的預處理巨集

2021-04-06 22:06:40 字數 3296 閱讀 2320

現代c++中的預處理巨集

--徐東來

摘要:在c++從c繼承的遺產中,預處理巨集是其中的一部分。在現代c++的發展過程中,預處理巨集是否還有意義?本文將討論之。

關鍵字:

預處理 巨集#define #pragma

c++中有那麼多靈活的特性,例如過載、型別安全的模板、const關鍵字等等,為什麼程式設計師還要寫「#define」這樣的預處理指令?

典型的乙個例子,大家都知道「const int a=100;」就比「#define a 100」要好,因為const提供型別安全、避免了預處理的意外修改等。

然而,還是有一些理由讓我們去使用#define。

1)守護標頭檔案

為了防止標頭檔案被多次包含,這是一種常用技巧。

#ifndef myprog_x_h

#define myprog_x_h

// … 標頭檔案x.h的其餘部分

#endif

2)使用預處理特性

在除錯**中,插入行號或編譯時間這類資訊通常很有用,可以使用預定義的標準巨集,例如__file__、__line__、__date__和__time__。

3)

編譯時期選擇**

a.除錯**

選擇性的輸出一些除錯資訊:

void f()

通常我們也可以用條件判斷來代替:

void f()

// .. f()的其他部分

} b.

特定平台**

同一函式同一功能在不同的編譯平台上可能有不同的表現形式,我們可以通過定義巨集來區分不同的平台。

c.不同的資料表示方式

《深入淺出mfc>>這本書對mfc框架中巨集的使用解析的很透徹,也讓我們領略到巨集的強大功能。可以參看declare_message_map(),

begin_message_map,

end_message_map的實現。

4)#pragma的使用,例如用#pragma禁止掉無傷大雅的警告,用於可移植性的條件編譯中。例如,

包含winsock2 lib檔案:

#pragma comment(lib,

」ws2_32」)

用如下預處理巨集,可以使結構按1字結對齊:

#pragma pack(push)

#pragma pack(1)

// …

結構定義

#pragma pack(pop)

禁止掉某些警告資訊:

#pragma warning( push )

#pragma warning( disable : 4705 )

#pragma warning( disable : 4706 )

#pragma warning( error : 164 )// 把164號警告作為錯誤報出

// some code

#pragma warning( pop )

下面示範如何寫乙個簡單的預處理巨集max();這個巨集有兩個引數,比較並返回其中較大的乙個值。在寫這樣乙個巨集時,容易犯哪些錯誤?有四大易犯錯誤。

1)不要忘記為引數加上括號

// 例1:括號陷阱一:引數

//

#define max(a, b) a < b ? b : a

例如:max(i += 2, j)

展開後:

i += 2 < j ? j : i += 2

考慮運算子優先順序和語言規則,實際上是:

i += ((2 < j) ? j : i += 2)

這種錯誤可能需要長時間的除錯才可以發現。

2)不要忘記為整個展開式加上括號

// 例2:括號陷阱二:展開式

//

#define max(a, b) (a) < (b) ? (b) : (a)

例如:

m = max(j, k) + 42;

展開後為:

m = (j) < (k) ? (j) : (k) + 42;

考慮運算子優先順序和語言規則,實際上是:

m = ((j) < (k)) ? (j) : ((k) + 42);

如果j >= k, m被賦值k+42,正確;如果j < k, m被賦值j,是錯誤的。如果給展開式加上括號,就解決了這個問題。

3)當心多引數運算

// 例3:多引數運算

//

#define max(a, b) ((a) < (b) ? (b) : (a))

max(++j, k);

如果++j的結果大於k,j會遞增兩次,這可能不是程式設計師想要的:

((++j) < (k) ? (k) : (++j))

類似的:

max(f(), pi)

展開後:

((f()) < (pi) ? (pi) : (f()))

如果f()的結果大於等於pi,f()會執行兩次,這絕對缺乏效率,而且可能是錯誤的。

4)

名字衝突

巨集只是執行文字替換,而不管文字在哪兒,這意味著只要使用巨集,就要小心對這些巨集命名。具體來說,這個max巨集最大的問題是,極有可能會和標準的max()函式模板衝突:

// 例4:名字衝突

//

#define max(a,b) ((a) < (b) ? (b) : (a))

#include // 衝突!

在中,有如下:

templateconst t&

max(const t& a, const t& b);

巨集將它替換為如下,將無法編譯:

templateconst t&

((const t& a) < (const t& b) ? (const t& b) : (const t& a));

所以,我們盡量避免命名的衝突,想出乙個不平常的,難以拼寫的名字,這樣才能最大可能地避免與其他名字空間衝突。

巨集的其他缺陷:

5)巨集不能遞迴

容易理解。

6)

巨集沒有位址

你可能得到任何自由函式或成員函式的指標,但不可能得到乙個巨集的指標,因為巨集沒有位址。巨集之所以沒有位址,原因很顯然===巨集不是**,巨集不會以自身的形勢存在,因為它是一種被美化了的文字替換規則。

7)

巨集有礙除錯

在編譯器看到**之前,巨集就會修改相應的**,因而,他會嚴重改變變數名稱和其他名稱;此外,在除錯階段,無法跟蹤到巨集的內部。

C 預處理 巨集定義

開發乙個 c語言程式,讓它暫停 5 秒以後再輸出內容 helllo 並且要求跨平台,在 windows 和 linux 下 include 說明 在windows 作業系統和 linux作業系統下,生成原始碼不一樣 if win32 如果是windows平台,就執行 include elif lin...

C語言 巨集定義,預處理巨集

巨集是學習任何語言所不可缺少的,優秀的巨集定義可以使得 變得很簡潔且高效,有效地提高程式設計效率。巨集是一種預處理指令,它提供了一種機制,可以用來替換源 中的字串,直譯器或編譯器在遇到巨集時會自動進行這一模式替換 c語言有簡單的巨集系統,由編譯器或彙編器的預處理器實現。c的巨集預處理器的工作只是簡單...

c語言預處理 巨集定義

個人筆記 巨集定義對於用c語言程式設計的人是經常用,這裡只講使用中需注意的問題點和方便的用法。1.巨集擴充套件中空格對擴充套件結果的影響 define a y a expanded y a x 被擴充套件為 a expanded x define a y a expanded y a x 被擴充套件...