• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            twzheng's cppblog

            『站在風(fēng)口浪尖緊握住鼠標(biāo)旋轉(zhuǎn)!』 http://www.cnblogs.com/twzheng

              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
              136 隨筆 :: 78 文章 :: 353 評(píng)論 :: 0 Trackbacks
             

            現(xiàn)代C++中的預(yù)處理宏

            --徐東來

            摘要:C++從C繼承的遺產(chǎn)中,預(yù)處理宏是其中的一部分。在現(xiàn)代C++的發(fā)展過程中,預(yù)處理宏是否還有意義?本文將討論之。

            關(guān)鍵字:預(yù)處理 宏 #define #pragma

             

               C++中有那么多靈活的特性,例如重載、類型安全的模板、const關(guān)鍵字等等,為什么程序員還要寫“#define”這樣的預(yù)處理指令?

               典型的一個(gè)例子,大家都知道“const int a=100;”就比“#define a 100”要好,因?yàn)閏onst提供類型安全、避免了預(yù)處理的意外修改等。

               然而,還是有一些理由讓我們?nèi)ナ褂?define。

            一、使用預(yù)處理宏

            1)   守護(hù)頭文件

            為了防止頭文件被多次包含,這是一種常用技巧。

            #ifndef MYPROG_X_H

            #define MYPROG_X_H

            // … 頭文件x.h的其余部分

            #endif

            2)   使用預(yù)處理特性

            在調(diào)試代碼中,插入行號(hào)或編譯時(shí)間這類信息通常很有用,可以使用預(yù)定義的標(biāo)準(zhǔn)宏,例如__FILE__、__LINE__、__DATE__和__TIME__。

            3)   編譯時(shí)期選擇代碼

            A. 調(diào)試代碼

            選擇性的輸出一些調(diào)試信息:

            void f()

            {

            #ifdef _DEBUG

               cerr<<”調(diào)試信息”<<endl;

            #endif

            // .. f()的其他部分

            }

            通常我們也可以用條件判斷來代替:

            void f()

            {

               if(_DEBUG)

               {

               cerr<<”調(diào)試信息”<<endl;

            }

            // .. f()的其他部分

            }

            B. 特定平臺(tái)代碼

            同一函數(shù)同一功能在不同的編譯平臺(tái)上可能有不同的表現(xiàn)形式,我們可以通過定義宏來區(qū)分不同的平臺(tái)。

            C. 不同的數(shù)據(jù)表示方式

            <<深入淺出MFC>>這本書對(duì)MFC框架中宏的使用解析的很透徹,也讓我們領(lǐng)略到宏的強(qiáng)大功能。可以參看DECLARE_MESSAGE_MAP(),

            BEGIN_MESSAGE_MAP, END_MESSAGE_MAP的實(shí)現(xiàn)。

            4)   #pragma的使用,例如用#pragma禁止掉無傷大雅的警告,用于可移植性的條件編譯中。例如,

            包含winsock2 lib文件:

            #pragma comment(lib,ws2_32)

            用如下預(yù)處理宏,可以使結(jié)構(gòu)按1字結(jié)對(duì)齊:

            #pragma pack(push)

            #pragma pack(1)

            // 結(jié)構(gòu)定義

            #pragma pack(pop)

                 禁止掉某些警告信息:

            #pragma warning( push )

            #pragma warning( disable : 4705 )

            #pragma warning( disable : 4706 )

            #pragma warning( error : 164 )// 把164號(hào)警告作為錯(cuò)誤報(bào)出

            // Some code

            #pragma warning( pop )

             

            二、宏的常見陷阱

               下面示范如何寫一個(gè)簡(jiǎn)單的預(yù)處理宏max();這個(gè)宏有兩個(gè)參數(shù),比較并返回其中較大的一個(gè)值。在寫這樣一個(gè)宏時(shí),容易犯哪些錯(cuò)誤?有四大易犯錯(cuò)誤。

            1)   不要忘記為參數(shù)加上括號(hào)

            // 例1:括號(hào)陷阱一:參數(shù)

            //

            #define max(a, b) a < b ? b : a

            例如:

            max(i += 2, j)

            展開后:

            i += 2 < j ? j : i += 2

            考慮運(yùn)算符優(yōu)先級(jí)和語言規(guī)則,實(shí)際上是:

            i += ((2 < j) ? j : i += 2)

            這種錯(cuò)誤可能需要長時(shí)間的調(diào)試才可以發(fā)現(xiàn)。

            2)   不要忘記為整個(gè)展開式加上括號(hào)

            // 例2:括號(hào)陷阱二:展開式

            //

            #define max(a, b) (a) < (b) ? (b) : (a)

               例如:

               m = max(j, k) + 42;

               展開后為:

               m = (j) < (k) ? (j) : (k) + 42;

            考慮運(yùn)算符優(yōu)先級(jí)和語言規(guī)則,實(shí)際上是:

               m = ((j) < (k)) ? (j) : ((k) + 42);

               如果j >= k, m被賦值k+42,正確;如果j < k, m被賦值j,是錯(cuò)誤的。如果給展開式加上括號(hào),就解決了這個(gè)問題。

            3)   當(dāng)心多參數(shù)運(yùn)算

            // 例3:多參數(shù)運(yùn)算

            //

            #define max(a, b) ((a) < (b) ? (b) : (a))

            max(++j, k);

               如果++j的結(jié)果大于k,j會(huì)遞增兩次,這可能不是程序員想要的:

            ((++j) < (k) ? (k) : (++j))

               類似的:

            max(f(), pi)

            展開后:

            ((f()) < (pi) ? (pi) : (f()))

            如果f()的結(jié)果大于等于pi,f()會(huì)執(zhí)行兩次,這絕對(duì)缺乏效率,而且可能是錯(cuò)誤的。

            4)   名字沖突

            宏只是執(zhí)行文本替換,而不管文本在哪兒,這意味著只要使用宏,就要小心對(duì)這些宏命名。具體來說,這個(gè)max宏最大的問題是,極有可能會(huì)和標(biāo)準(zhǔn)的max()函數(shù)模板沖突:

            // 例4:名字沖突

            //

            #define max(a,b) ((a) < (b) ? (b) : (a))

            #include <algorithm> // 沖突!

            <algorithm>中,有如下:

            template<typename T> const T&

            max(const T& a, const T& b);

            宏將它替換為如下,將無法編譯:

            template<typename T> const T&

            ((const T& a) < (const T& b) ? (const T& b) : (const T& a));

            所以,我們盡量避免命名的沖突,想出一個(gè)不平常的,難以拼寫的名字,這樣才能最大可能地避免與其他名字空間沖突。

             

            宏的其他缺陷:

            5)   宏不能遞歸

               容易理解。

            6)   宏沒有地址

            你可能得到任何自由函數(shù)或成員函數(shù)的指針,但不可能得到一個(gè)宏的指針,因?yàn)楹隂]有地址。宏之所以沒有地址,原因很顯然===宏不是代碼,宏不會(huì)以自身的形勢(shì)存在,因?yàn)樗且环N被美化了的文本替換規(guī)則。

            7)   宏有礙調(diào)試

            在編譯器看到代碼之前,宏就會(huì)修改相應(yīng)的代碼,因而,他會(huì)嚴(yán)重改變變量名稱和其他名稱;此外,在調(diào)試階段,無法跟蹤到宏的內(nèi)部。

            posted on 2007-04-23 23:19 譚文政 閱讀(656) 評(píng)論(0)  編輯 收藏 引用 所屬分類: C/C++
            亚洲午夜精品久久久久久app| 狠狠综合久久综合88亚洲| 久久久久久午夜成人影院| 亚洲精品蜜桃久久久久久| 久久亚洲精品人成综合网| 日韩亚洲欧美久久久www综合网 | 国产精品久久久天天影视| 国产三级精品久久| 色播久久人人爽人人爽人人片AV| 久久天天躁狠狠躁夜夜网站| 伊人久久大香线蕉影院95| 亚洲中文字幕无码久久2017| 观看 国产综合久久久久鬼色 欧美 亚洲 一区二区 | 91精品国产91热久久久久福利| 热re99久久精品国99热| 久久国产精品免费| 国产精品久久久亚洲| 久久伊人五月丁香狠狠色| 精品99久久aaa一级毛片| 91精品国产9l久久久久| 亚洲AV无码久久精品蜜桃| 亚洲?V乱码久久精品蜜桃 | 久久人爽人人爽人人片AV| 欧美国产精品久久高清| 99热成人精品免费久久| 国产一区二区精品久久| 无码人妻久久久一区二区三区 | 亚洲国产成人久久精品99| 久久97久久97精品免视看| 亚洲国产精品久久66| 久久精品国产半推半就| 久久99精品久久只有精品| 日韩人妻无码精品久久免费一 | 中文字幕精品久久久久人妻| 狠狠色伊人久久精品综合网| 久久国产精品久久精品国产| 狠狠色丁香久久综合婷婷| 9久久9久久精品| 99热都是精品久久久久久| 久久久久国产精品嫩草影院 | 久久精品国产男包|