C++ 避免使用宏

概述:

        宏是C和C++語言的抽象設施中最生硬的工具,它是披着函數外衣的飢餓的狼,很難馴服,它會我行我素地遊走於各處。要避免使用宏。

討論:

        在C++中,幾乎從不需要使用宏。

        可以用const或者enum定義易於理解的常量,用inline避免函數調用的開銷,用template指定函數系列和類型系列,用namespace避免名稱衝突。

    C++的宏的主要問題在於,它們表面上看起來很好,而實際上做的卻是另一回事。宏會忽略作用域,忽略類型系統,忽略所有其他的語言特性和規則,而且會劫持它爲文件其餘部分所定義(#define)的符號。宏調用看上去很像符號或者函數調用,但實際上並非如此。宏不太“衛生”,也就是說,它會根據自己被使用時所處的環境引人注目而且令人驚奇地展開爲各種東西。宏需要進行文本替換,因此編寫遠距離也正確的宏接近於一種魔法,而精通這種魔法既無意義又無趣味。

    不少人認爲與模板相關的錯誤都是最難以解讀的,他們可能還沒有看到誤寫和誤用的宏所引起的那些錯誤。模板是C++類型系統的一部分,因此編譯器可以更好地對它們進行處理,而宏天生是與語言本身割裂開來的,因此很難處理。更糟的是,與模板不同,宏可能展開爲在偶然情況下能夠編譯的“傳輸線噪音”。最後,宏中的錯誤可能只有在宏展開之後才能被報告出來,而不是在定義時。

     即使在極少的情況下,有正當理由編寫宏,也決不要考慮編寫一個以常見詞或者縮略語爲名字的宏。儘可能快的取消宏的定義(#undef)。

示例:

    1、定義一個宏#define  min(n, m)    ((n) < (m) ? (n) : (m)) 

            定義兩個變量a和b,min(++a, b) 傳入之後是這樣 ((++a) < (b) ? (++a) : (b))   如果++a小於b的話,a就自加了兩次,很明顯不符合宏使用的初衷。

    2、將模板實例化轉給宏,宏僅能理解C語言的小括號和方括號,並將其進行匹配。然而,C++又定義了一個新的括號結構,即模板中使用的尖括號<和>。宏無法正確的匹配它們,這意味着在下面的宏調用中:

       MACRO(Foo<int,double>)

       宏會認爲傳給自己的是兩個參數,即Foo<int和double>,而事實上該結構是一個C++實體。

例外情況:

    宏仍然是幾個重要任務的唯一解決方案,比如#include保護符,條件編譯中的#ifdef和#ifndef,以及assert的實現。

    在條件編譯中,要避免在代碼中到處雜亂地插入#ifdef。相反,應該對代碼進行組織,利用宏在驅動一個公共接口的多個實現,然後始終使用該接口。

    如果不想到處複製粘貼代碼段,那麼可以使用宏,但要非常小心。
       


      來自:《C++編程規範》


宏需要進行文本替換,例子:

#include<iostream>

using namespace std;

#define p(x) (x*x)

int main(void)

{ int a,b=3;  

a=p(b+2);  

cout<<a<<endl;  

return 0;

}


宏就是按照要代替的代碼原樣展開
#define p(x) (x*x)
int a,b=3;
a=p(b+2);
展開就是 a = b+2*b+2;

a = 3+2*3+2=11;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章