在c及c++語言中允許用乙個識別符號來表示乙個字串,稱為巨集,該字串可以是常數、表示式、格式串等。在編譯預處理時,對程式中所有出現的「巨集名」,都用巨集定義中的字串去代換,這稱為「巨集代換」或「巨集展開」。巨集定義是由源程式中的巨集定義命令完成的。巨集代換是由預處理程式自動完成的。若字串是表示式,我們稱之為函式式巨集定義。
我們以下面兩行**為例,展開描述:
函式式巨集定義:#define max(a,b) ((a)>(b)?(a):(b))
普通函式 :max(a,b)
(1)函式式巨集定義的引數沒有型別,預處理器只負責做形式上的替換,而不做引數型別檢查,所以傳參時要格外小心。
(2)函式式巨集定義要注意格式,尤其是括號。
這個巨集定義的外層括號也是不能省的。若函式中是巨集替換為 ++max(a,b),則巨集展開就成了 ++(a)>(b)?(a):(b),運算優先順序也是錯了。同理,記憶體括號也不要省。
(3)若函式引數為表示式,則普通函式的呼叫與函式式巨集定義的替換過程是不一樣的。
普通函式呼叫時先求實參表示式的值再傳給形參,如果實參表示式有side effect,那麼這些sideeffect只發生一次。例如max(++a, ++b),如果max是普通函式,a和b只增加一次。但如果max函式式巨集定義,則要展開成k = ((++a)>(++b)?(++a):(++b)),a和b就不一定是增加一次還是兩次了。所以若引數是表示式,替換函式式巨集定義時一定要仔細看好。
(4)呼叫真正函式的**和呼叫函式式巨集定義的**編譯生成的指令不同。
如果max是個普通函式,那麼它的函式體return a > b ? a : b; 要編譯生成指令,**中出現的每次呼叫也要編譯生成傳參指令和call指令。而如果max是個函式式巨集定義,這個巨集定義本身倒不必編譯生成指令,但是**中出現的每次呼叫編譯生成的指令都相當於乙個函式體,而不是簡單的幾條傳參指令和call指令。所以,使用函式式巨集定義編譯生成的目標檔案會比較大。
函式式巨集定義與普通函式
函式式巨集定義與普通函式 在 及c 語言中允許用乙個識別符號來表示乙個字串,稱為巨集,該字串可以是常數 表示式 格式串等。在編譯預處理時,對程式中所有出現的 巨集名 都用巨集定義中的字串去代換,這稱為 巨集代換 或 巨集展開 巨集定義是由源程式中的巨集定義命令完成的。巨集代換是由預處理程式自動完成的...
函式式巨集定義與普通函式
在 及c 語言中允許用乙個識別符號來表示乙個字串,稱為巨集,該字串可以是常數 表示式 格式串等。在編譯預處理時,對程式中所有出現的 巨集名 都用巨集定義中的字串去代換,這稱為 巨集代換 或 巨集展開 巨集定義是由源程式中的巨集定義命令完成的。巨集代換是由預處理程式自動完成的。若字串是表示式,我們稱之...
函式式巨集定義與普通函式
在 及c 語言中允許用乙個識別符號來表示乙個字串,稱為巨集,該字串可以是常數 表示式 格式串等。在編譯預處理時,對程式中所有出現的 巨集名 都用巨集定義中的字串去代換,這稱為 巨集代換 或 巨集展開 巨集定義是由源程式中的巨集定義命令完成的。巨集代換是由預處理程式自動完成的。若字串是表示式,我們稱之...