C語言 巨集定義與函式的區別

2021-10-11 01:16:58 字數 1753 閱讀 9671

在**開發過程中,有一些常用或者可以通用的功能或者**段,實現這些功能,既可以寫成函式,也可以封裝成為巨集定義。那麼究竟是用函式好,還是巨集定義好?這就要求我們對二者進行合理的取捨。

巨集: #define 機制包括了乙個規定,允許把引數替換到文字中,這種實現常常稱為巨集,或者巨集定義。

巨集對變數的***:

#define square(x)  (x * x)     //常見的求平方
然後求平方

square(5)
預處理器就會用  5 * 5 這個表示式替換上面的表示式,結果是 25,符合你的預期。

但是請看下面乙個:

int a = 5;

printf(" (5 + 1) square: %d\n", square( 5 + 1));

結果是:11 不符合你的預期

實際在執行時, 使用 5 + 1 * 5 + 1 替換了上面的表示式, 結果就是11, 不符合你的預期, 這種是最常見的相鄰的操作符優先順序, 大於你傳入引數需要優先執行操作符的優先順序.

類似的還有 a++ 這樣的操作, 都會帶來***.

巨集對引數的***,在使用自定義函式時就不會產生:

int get_square(int a)

呼叫 get_square(5+1)時, 不會產生引數的***, 程式執行時, 會先算出5+1的和, 然後再傳入函式去執行。

先看一下《c與指標》中的巨集定義「函式」與自定義介面的區別:

巨集與函式的區別

屬性#define 巨集

函式**長度

每次呼叫時,巨集**都會被插入到程式中。除了非常小的巨集之外,程式的長度將大幅增加

函式**只出現在乙個地方,每次呼叫這個函式時,呼叫的都是那個地方的同乙份**

執行速度

更快存在函式呼叫/返回的額外開銷

操作符優先順序

巨集引數的求值是在所有周圍下上文環境裡,除非給它們加上括號,否則鄰近操作符的優先順序,可能會產生不可**的結果

函式引數只在函式呼叫時求值一次,它的結果值傳遞給函式。表示式的求值更容易**。

引數求值

引數每次用於巨集定義時。它們都將重新求值,由於多次求值,具有***的引數可能會產生不可預料的結果。

引數在函式被呼叫前只求值一次,在函式中多次使用引數,並不會導致多種求值過程,引數的***並不會造成任何特殊問題

引數型別

巨集與型別無關,只要引數的操作是合法的,它可以適用於任何引數型別

函式的引數是與型別有關的,如果引數的型別不同,就需要使用不同的函式,即使它們的任務是相同的

我們常用到的比較大小,巨集定義:

#define max( a, b) ( (a) > (b) (a) : (b) )
自定義介面實現就是:

int max( int a, int b)

區別:

1. 最直觀的來講,自定義的函式已經指定了型別,只能比較兩個整數的大小,卻不能再去比較浮點數的大小,或者兩個ascii碼的大小;而巨集定義是不會限定型別的,只要比較的型別一致即可。

2. 自定義介面在程式執行時,會產生臨時的堆空間,有臨時的空間消耗,如果是遞迴的話,需要的臨時棧空間可能更多;巨集定義是在程式執行時,會將巨集定義這段**插入到程式中執行,會有額外的**段。

3. 自定義介面在呼叫時,實際的開銷要比**段大,規模更大; 而巨集比自定義函式在程式的規模和速度方面,比自定義函式更勝一籌。

C語言中巨集定義函式與普通函式的區別

在 及c 語言中允許用乙個識別符號來表示乙個字串,稱為巨集,該字串可以是常數 表示式 格式串等。在編譯預處理時,對程式中所有出現的 巨集名 都用 巨集定義中的字串去代換,這稱為 巨集代換 或 巨集展開 巨集定義是由源程式中的巨集定義命令完成的。巨集代換是由預處理程式自動完成的。若字串是表示式,我們稱...

C 內聯函式與巨集定義的區別

c primer 5th editon p213 消除 函式呼叫 執行時開銷 內聯函式與巨集定義的區別 內聯函式在執行時可除錯,而巨集定義不可以 編譯器會對內聯函式的引數型別做安全檢查或自動型別轉換 同普通函式 而巨集定義則不會 內聯函式可以訪問類的成員變數,巨集定義則不能 在類中宣告同時定義的成員...

C語言巨集定義和巨集定義函式

c語言巨集定義和巨集定義函式 巨集定義可以幫助我們防止出錯,提高 的可移植性和可讀性等。在軟體開發過程中,經常有一些常用或者通用的功能或者 段,這些功能既可以寫成函式,也可以封裝成為巨集定義。那麼究竟是用函式好,還是巨集定義好?這就要求我們對二者進行合理的取捨。我們來看乙個例子,比較兩個數或者表示式...