VC預處理指令與巨集定義的妙用

2021-05-28 03:07:00 字數 3642 閱讀 1082

vc預處理指令與巨集定義的妙用

2023年04月02日 星期三 下午 06:36

vc預處理指令與巨集定義的妙用

剛接觸到mfc程式設計的人往往會被mfc 嚮導生成的各種巨集定義和預處理指令所嚇倒,但是預處理和巨集定義又是c語言的乙個強大工具。使用它們可以進行簡單的源**控制,版本控制,預警或者完成一些特殊的功能。

乙個經典的例子

使用預處理與巨集定義最經典的例子莫過於加在乙個標頭檔案中以避免標頭檔案被兩次編譯。試想這種的情況,有乙個檔案headerfile.h 它被包含在headerfile1.h中,同時在headerfile2.h 中也被包含了,現在有乙個cpp檔案,implement.cpp 包含了headerfile1.h 和headerfile2.h:

#include 「headerfile1.h」

#include 「headerfile2.h」

假設headerfile.h 中定義了乙個全域性變數 iglobal .

int iglobal;

在編譯的時候編譯器兩次編譯headerfile,也就會發現iglobal被定義了兩次,這時就會發生變數重定義的編譯錯誤。

傳統的解決辦法是使用#ifdef 以及#endif 來避免標頭檔案的重複編譯,在上面的例子中,只需要加上這麼幾行:

#ifndef smartnose_2002_6_21_headerfile_h

#define smartnose_2002_6_21_headerfile_h

int iglobal;

#endif

仔細的考慮上面的巨集定義,會發現當編譯器編譯過一次headerfile.h以後,smartnose_2002_6_21_headerfile_h 這個巨集就被定義了,以後對headerfile.h的編譯都會跳過int iglobal 這一行。當然smartnose_2002_6_21_headerfile_h 這個巨集是可以任意定義的,但是這個巨集本身不能和其它檔案中定義的巨集重複,所以mfc在自動生成的檔案中總是使用乙個隨機產生的長度非常長的巨集,但我覺得這沒有必要,我建議在這個巨集中加入一些有意義的資訊,比方作者,檔名,檔案建立時間等等,因為我們有時候會忘記在注釋中加入這些資訊。

在vc.net 中我們不會再看見這些巨集定義了,因為在這裡會普遍使用乙個預處理指令:

#pragma once

只要在標頭檔案的最開始加入這條指令就能夠保證標頭檔案被編譯一次,這條指令實際上在vc6中就已經有了,但是考慮到相容性並沒有太多的使用它。

源**版本控制

當我們為許多平台開發多個版本的時候預編譯指令和巨集定義也能夠幫我們的忙。假設我們現在為windows 和linux開發了一套軟體,由於這兩種系統的不同,我們不得不在程式控制源**的版本。比方記憶體的分配,我們可以在linux上使用標準c的malloc 函式,但是我們希望在 windows上使用heapalloc api.下面的**演示了這種情況:

main()

#ifdef _windows_platform

heapalloc(5);

#else

malloc(5);

#endif

當我們在windows 平台上編譯此程式的時候,只需要定義_windows_platform這個巨集,那麼heapalloc這條語句就能夠起作用了。這樣就能夠讓我們在同乙個檔案中為不同的平台實現不同版本的**,同時保持程式的良好結構。在許多情況下,我們還可以為乙個方法使用不同的演算法,然後用巨集定義來針對不同的情況選擇其中的乙個進行編譯。這在mfc應用程式中是使用得最多的。最明顯的就是檔案中經常存在的

#ifdef _debug

……………………。some code……………

#endif

這樣的**,這些**在應用程式的除錯版(debug)中會發揮其作用。

#pragma 指令

在所有的預處理指令中,#pragma 指令可能是最複雜的了,它的作用是設定編譯器的狀態或者是指示編譯器完成一些特定的動作。其格式一般為

#pragma para

其中para 為引數,下面來看一些常用的引數。

message 引數。 message 引數是我最喜歡的乙個引數,它能夠在編譯資訊輸出視窗中輸出相應的資訊,這對於源**資訊的控制是非常重要的。其使用方法為:

#pragma message(「訊息文字」)

當編譯器遇到這條指令時就在編譯輸出視窗中將訊息文字列印出來。

當我們在程式中定義了許多巨集來控制源**版本的時候,我們自己有可能都會忘記有沒有正確的設定這些巨集,此時我們可以用這條指令在編譯的時候就進行檢查。假設我們希望判斷自己有沒有在源**的什麼地方定義了_x86這個巨集可以用下面的方法

#ifdef _x86

#pragma message(「_x86 macro activated!」)

#endif

當我們定義了_x86這個巨集以後,應用程式在編譯時就會在編譯輸出視窗裡顯示「_x86 macro activated!」。我們就不會因為不記得自己定義的一些特定的巨集而抓耳撓腮了。

另乙個使用得比較多的pragma引數是code_seg.格式如:

#pragma code_seg( ["section-name"[,"section-class"] ] )

它能夠設定程式中函式**存放的**段,當我們開發驅動程式的時候就會使用到它。

最後乙個比較常用的就是上面所說的#pragma once 指令了。

vc預定義的巨集

在vc中有一類巨集並不是由使用者用#define語句定義的,而是編譯器本身就能夠識別它們。這些巨集的作用也是相當大的。讓我們來看第乙個,也是mfc中使用得最頻繁的乙個:__file__ .

當編譯器遇到這個巨集時就把它展開成當前被編譯檔案的檔名。好了,我們馬上就可以想到可以用它來做什麼,當應用程式發生錯誤時,我們可以報告這個錯誤發生的程式**在哪個檔案裡,比方在檔案test.cpp中有這樣的**:

trychar * p=new(char[10]);

catch(cexception *e )

trace(「 there is an error in file: %s\n」,__file__);

在程式執行的時候,如果記憶體分配出現了錯誤,那麼在除錯視窗中會出現there is an error in file: test.cpp 這句話,當然,我們還可以把這個錯誤資訊顯示在別的地方。

如果我們還能夠記錄錯誤發生在哪一行就好了,幸運的是,與__file__巨集定義一樣,還有乙個巨集記錄了當前**所在的行數,這個巨集是__line__.使用上面的兩個巨集,我們可以寫出乙個類似於vc提供的assert語句。下面是方法

#define myassert(x) \

if(!(x)) \

messagebox(__file__,__line__,null,mb_ok);

我們在應用程式中可以象使用assert語句一樣使用它,在錯誤發生時,它會彈出乙個對話方塊,其標題和內容告訴了我們錯誤發生的檔案和**行號,方便我們的除錯,這對於不能使用assert語句的專案來說是非常有用的。

除了這兩個巨集以外,還有記錄編譯時間的__time__,記錄日期的__date__,以及記錄檔案修改時間的__timestamp__巨集。

使用這些預定義的巨集,我們幾乎可以生成和vc能夠生成的一樣完整的源**資訊報表。

結論翻開mfc和linux的源**,巨集定義幾乎佔據了半邊天,訊息對映,佇列操作,平台移植,版本管理,甚至核心模組的拆卸安裝都用巨集定義完成。毫不誇張的說,有些檔案甚至就只能看見巨集定義。所以學習巨集定義,熟練的使用巨集定義對於學習c語言乃至vc都是非常關鍵的。

VC中預處理指令與巨集定義的妙用(1)

monday,june 24 2002 11 28 am 乙個經典的例子 被遮蔽廣告 使用預處理與巨集定義最經典的例子莫過於加在乙個標頭檔案中以避免標頭檔案被兩次編譯。試想這種的情況,有乙個檔案headerfile.h 它被包含在headerfile1.h中,同時在headerfile2.h 中也被...

預處理指令與巨集

剛接觸到mfc程式設計的人往往會被mfc 嚮導生成的各種巨集定義和預處理指令所嚇倒,但是預處理和巨集定義又是c語言的乙個強大工具。使用它們可以進行簡單的源 控制,版本控制,預警或者完成一些特殊的功能。乙個經典的例子 使用預處理與巨集定義最經典的例子莫過於加在乙個標頭檔案中以避免標頭檔案被兩次編譯。試...

預處理 巨集定義

1,預處理 預處理是指在進行編譯的第一遍掃瞄 詞法掃瞄和語法分析 之前所作的工作。預處理是 語言的乙個重要功能,它由預處理程式負責完成。當對乙個原始檔進行編譯時,系統將自動引用預處理程式對源程式中的預處理部分作處理,處理完畢自動進入對源程式的編譯。語言提供了多種預處理功能,如巨集定義 檔案包含 條件...