巨集跟函式及常量總結

2021-05-08 19:35:05 字數 2727 閱讀 8960

當你

呼叫乙個過程既被宣告成

函式又被宣告成巨集時,你可以用如下兩種方法來強制編譯器使用函式或巨集(編譯器缺省會使用巨集)。

1、使用強制

型別轉換

#include

a = toupper(a);                              //使用巨集

a = (toupper)(a);                           //使用函式,因為toupper被強制轉換成函式指標。

2、使用#undef

#include

#undef toupper                                   //注意這裡是小寫,以後呼叫過程toupper都為函式呼叫,因為巨集定義已被//取消。

那麼,我們應該怎樣來選擇在乙個

程式中使用巨集還是使用函式呼叫呢?

1、時間vs 大小

使用巨集時,因為巨集被就地展開,因此,用巨集編譯出來的**會比用函式編譯出來的**大。但巨集展開後沒有了函式的引數傳遞,所以執行起來比函式要快。

使用函式時因函式只是被多次執行,因此**小,但函式呼叫時增加了開銷。

2、函式可以通過函式指標來呼叫,而巨集則不行。 如:

int addone(int a) ;         //定義乙個函式

int (*plusone)(int a);                //定義乙個函式指標

pluseone = addone;                 //初始化函式指標

(*pluseone)(2);                        //通過函式指標呼叫函式

3、在多工併發執行的

應用程式中,使用函式時需考慮函式的重入

問題。巨集因為就地展開,因此,不用考慮重入問題。

4、使用巨集時,要注意巨集的引數有可能出錯。

a)         巨集定義不當出錯 如:

巨集定義#define f (x) (x+1)

現在假如有乙個如下所示的巨集呼叫:

f(1) 預

處理器展開它,出現下面不希望的情況:

(x) (x+1) (1)

出現這個問題是因為在巨集定義中f和括號之間存在空格,當這個空格取消後,呼叫巨集時可以有空格空隙,像下面的呼叫:

f (1)

依然可以正確地展開為:

(1+1)

b)        當巨集傳遞引數時出錯

如:優先順序不同出錯

#define floor(x,b) x>=b ? 0:1

現在假如用表示式作引數:

if(floor(a&0x0f,0x07))

巨集將展開成:

if(a&0x0f>=0x07 ? 0 : 1)

因為&的優先順序比》=的低,所以巨集的展開結果將會使我們驚訝。一旦發現這個問題,可以通過在巨集定義內的各個地方使用括弧來

解決,(這是建立預處理器巨集時使用的好方法。)上面的定義可改寫成如下:

#define floor(x,b)   ((x)>=(b) ? 0 : 1)

c)        當乙個巨集多次使用引數時出錯 如:

#define toupper(c)    ((islower(c)) ? _toupper(c) : (c))

#include

int a = 『m』;

a = toupper(a++);

程式執行後,a的值會加2;

上面的程式被編譯器展開後:

int a = 『m』;

a = islower(a++) ? _toupper(a++) : (a++);

由此可見,變數a被增加了兩次。

5、型別檢查

當定義為函式時,編譯器會檢查函式的引數,但定義為巨集時,編譯器只檢查引數的個數。

6、使用內聯函式(c++或支技內聯函式的編譯器中)

編譯器會根據內聯函式的執行時間和**長度來決定是展開內聯函式還是將內聯函式作為普通函式呼叫。(如果內聯函式內部有迴圈,則編譯器會把內聯函式當普通函式呼叫,因為迴圈執行的時間一般很長,相對於函式呼叫的時間來說,就地展開並不會提高**的效率。同樣,當函式較大時,由於需要在函式呼叫處的每一處重複複製**,這樣將使**膨脹,在速度方面獲得的好處就會減少,編譯器同樣不會展開這種內聯函式。)

a)       巨集不能定義在類裡:

如不能有如下或近似的定義

class x;

注意,編譯器將檢查函式引數列表是否正確,並返回值(進行必要的轉換)。這些事情是預處理器無法完成的。

c)        

常量跟巨集定義

預處理器在c語言中用名字替代值的典型用法是這樣的:

#define       bufsize 100

大多數情況,bufsize的工作方式與普通變數類似;而且沒有型別資訊。這就會隱藏一些很難發現的

錯誤。我們可以用const 常量來替代它。

const int bufsize = 100 ;

這樣就可以在編譯時編譯器需要知道這個值的任何地方使用bufsize,同時編譯器還可以執行常量摺疊(constant folding),也就是說,編譯器在編譯時可以通過必要的計算把乙個複雜的常量表示式通過縮減簡單化。這一點在陣列定義裡顯得尤為重要:

char   buf[bufsize];

指向const的指標(指標指向的內容不能改變)

const int* u;

int const * u;

const 指標(指標不能改變)

int d=1;

int * const w = &d;

C常量,巨集,列舉及函式

為什麼使用常量 防止資料在程式中被任意修改,造成前後不一致,可以方便批量進行調整,能做到快捷,方便,安全 常量 直接常量 命名常量 const關鍵字,define定義 巨集語句 eg 巨集定義不需要型別,只是文字替換 為什麼使用列舉 提高 可讀性,便於程式維護,enum關鍵字 列舉的值 列舉型別定義...

Objective C中的常用數學常量巨集及函式

在實際工作中有些程式不可避免的需要使用數學函式進行計算,比如地圖程式的地理座標到地圖座標的變換。objective c做為ansi c的擴充套件,使用c標準庫標頭檔案中定義的數學常量巨集及數學函式來實現基本的數學計算操作,所以不必費神再在cocoa foundation中尋找相應的函式和類了。這裡列...

Objective C中的常用數學常量巨集及函式

在實際工作中有些程式不可避免的需要使用數學函式進行計算,比如地圖程式的地理座標到地圖座標的變換。objective c做為ansic的擴充套件,使用c標準庫標頭檔案中定義的數學常量巨集及數學函式來實現基本的數學計算操作,所以不必費神再在cocoafoundation中尋找相應的函式和類了。這裡列出一...