宏在C++中的替代解決方案

來源:互聯網
上載者:User

宏在C++中的替代解決方案

     宏,在C語言中是個神的存在,能夠玩出各種花樣,也正因為此,才會給普通程式員造成不少的困擾。由於宏只在先行編譯階段起作用,使得編譯器無法檢測其中的Bug,作為新時代的C++程式員,還是遠離的好。

C++為宏提供了一些替代的解決方案,嗯,是一些。

 

1. 常量定義

#define NUM 100

《EffectiveC++》的第一個條款,討論的就是這個宏。由於宏是先行編譯程式來處理,所以NUM這個名字不會加入到符號表中,如果出現編譯錯誤時,提示資訊中就不會出現NUM,而是100,為排除錯誤增加了額外的障礙。

替代方案就是使用const來定義常量,或者使用枚舉enum。

const int NUM = 100;

const常量放在標頭檔中,也不必擔心存在多個執行個體的問題,對於const修飾的變數,編譯器一般也會對其進行最佳化,不會出現多重定義的問題。

 

C語言中還有一個特殊的常量定義:NULL。其一般的定義為 #define NULL 0,指標的內容卻是一個整型,這不符合常理。所以在C++11中使用nullptr代替了NULL。

 

2.函數定義

由於宏只是在代碼中做字串替代展開,所以,用宏定義的函數,實際上並沒有減少代碼的體積。另外,還有一些天然的缺陷,假設一個求平方的函數宏

#definesquare(x)  (x*x)voidf(double d, int i){square(d); //OKsquare(i++); //糟糕, (i++*i++)square(d+1); //更糟,(d+1*d+1)}

縱然可以把參數加上括弧來解決,#define square(x) ((x)*(x)),但i++被執行兩次這個問題還是無法解決。

C++中的替代方案,就是使用inline函數。

inline int square(intvalue){    return value*value;}

inline函數具有函數的性質,參數傳遞不管是傳值還是傳引用,都不會對參數進行重複計算;同時會對參數做類型檢查,保證代碼的正確性;inline函數也是在代碼中做代碼展開,效率上並不比宏遜色。

如果整型不滿足需求,還可以定義為模板:

template<classT>inline T square(T& value){    return value*value;}

還有一種更離譜的函數定義形式: 

#defineNull_Check(p)\if(p == NULL) return;

這種使用反斜線定義的函數,更得注意,如果在反斜線後多了個空格的話,有的編譯器會出現變異錯誤,而提示資訊嘛,你可能會困擾很久的。因為反斜線會對空格這個字元做反義,就會在代碼中的引入非法字元,人眼是很難發現這種錯誤的。

 

3.類型重定義

#defineDWORD unsigned int

這種類型重定義完全可以使用 typedef unsigned int DWORD 來替代。

 

4.條件編譯

#ifdefSystemAtestA();#else//SystemBtestB();#endif

 

這種條件編譯宏,一般在不同的產品或平台使用同一套代碼的情況,大量出現。定義了SystemA的時候,SystemB的代碼是不編譯的,也就意味著你的代碼沒有時刻處於編譯器的監控中。可以使用template技術來解決。

 

constint SystemA = 1;constint SystemB = 2; template<int T>void test(){}//定義不同的系統的特化版本template<> void test<SystemA>(){ //SystemA的實現 }template<> void test<SystemB>(){ //SystemB的實現 } 

這樣,不同的系統使用自己的模板即可,別人的代碼也會同時接受編譯器的檢查,不至於出現遺漏編譯錯誤的情況。

 

5.標頭檔包含

#ifndeftest_h#definetest_h    //test.h的實現#endif

為了防止標頭檔重複包含,C++中現在也只能這麼做,目前沒有別的替代方案。且看看原委,Bjarne Stroustrup在《C++語言的設計與演化》一書中,提供了一個include的設計,可惜的是並沒有真正實現。(Cpp, 即C語言前置處理器)

我曾經建議可以給C++本身增加一個include指示字,作為Cpp的#include的替代品。C++的這種include可以在下面三個方面與Cpp的#include不同:

1)如果一個檔案被include兩次,第二個include將被忽略。這解決了一個實際問題,而目前這個問題是通過#define和#ifdef,以非常低效而笨拙的方式處理的。

2)在include的本文之外定義的宏將不在include的本文內部展開。這就提供了一種能夠隔離資訊的機制,可以使這些資訊不受宏的幹擾。

3)在include的本文內容定義的宏在include本文之後的本文處理中不展開。這保證了include本文內部的宏不會包含它的編譯模組強加上某種順序依賴性,並一般地防止了由宏引起的奇怪情況。

對於採用先行編譯標頭檔的系統而言一般地說,對於那些要用獨立部分組合軟體的人們而言,這種機制都將是一個福音。請注意,無論如何這還只是一個思想而不是一個語言特徵。

 

也就是說,這個想法在C++中並沒有實現。

 

如果你沒有很好的駕馭宏,那就敬而遠之吧。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.