• <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>
            posts - 16,  comments - 34,  trackbacks - 0

            題目有點繞口……

            問題見: http://bbs2.chinaunix.net/viewthread.php?tid=1373280

             

            問題描述

             

            問題解答

             


             

            問題分析

            需要注意:
            I. 宏是作文本替換
            II. 替換的終止條件是:文件中不再含有宏

            對第9行的:SET_NAME(1212)
            1. 首先根據I和第5行,SET_NAME(1212) 會被替換成:CONNECTION(test,1212)
            2. CONNECTION依然是一個宏,根據II,繼續替換
            3. 根據I和第4行,CONNECTION(test,1212),被替換為 test1212
            4. 所以第10行最終會被CPP替換成 "int test1212 = 1212;"

            對第12行的:SET_NAME(VAR)
            1. 首先根據I和第5行,SET_NAME(VAR)會被替換成:CONNECTION(test,VAR)
            2. CONNECTIONVAR依然是一個宏,根據II,繼續替換
            3. 根據I和第11行,CONNECTION(test,VAR)被替換為CONNECTION(test,326)
            4. 再根據I和第4行,CONNECTION(test,326)被替換為test326
            5. 所以第12行最終會被CPP替換成 "int test326 = 326;"

            對第16行的:SET_NAME(VAR),同第12行,最終會被替換成 test86



            為什么setname不行?
            setname(var) 會被替換成 testvar,而后者不再含有宏,替換終止


             

            常見應用

            根據行號命名——為了取一些相互不沖突的名字,使用行號作為后綴
            因為__LINE__也是一個,所以需要這種方法。

            例1,Loki::ScopeGuard

            Loki::ScopeGuard

             

            Loki::ScopeGuard MACRO 示例


             1// Loki::ScopeGuard macro sample
             2// Loki::ScopeGuard : 范型、輕量的RAII技術 ,對資源管理與異常安全提供非常強大的支持
             3// 該處僅演示使用__LINE__作變量后綴名的方法, 暫不討論Loki::ScopeGuard
             4
             5#include <cassert>
             6#include <cstdio>
             7#include <stdexcept>
             8#include <string>
             9#include <loki::ScopeGuard>
            10
            11void CopyFile(const char* input_file,const char* output_file) /* throw(std::exception) */ {
            12    using namescape std;
            13
            14    FILE* input = fopen(input_file,"r");
            15    if (!input) throw runtime_error( string("can't open input file :"+ input_file);
            16    LOKI_ON_BLOCK_EXIT(fclose,input);
            17
            18    FILE* output = fopen(output_file,"wb");
            19    if (!output) throw runtime_error( string("can't open output file :"+ output);
            20    LOKI_ON_BLOCK_EXIT(fclose,output);
            21
            22    enum { buf_size = 1212 };
            23    char buf[buf_size];
            24    size_t r = buf_size;
            25
            26    do {
            27        r = fread(buf,1,buf_size,input);
            28        if ( buf_size != fwrite(buf,1,buf_size,output)
            29            throw runtime_error( string("write output file : "+ output + " occurs an error" );
            30    }

            31    while ( r == buf_size );
            32
            33    if ( !feof(input) {
            34        assert( ferror(input) );
            35        throw runtime_error( string("read input file : "+ input + " occurs an error");
            36    }

            37}

            38
            39
            40int main() {
            41    try 
            44    catch (std::exception& e) 
            47}

            48


             代碼中16和20行,根據loki/ScopeGuard.h (658)中的定義,將被分別替換成:

            ::Loki::ScopeGuard scopeGuard16 = ::Loki::MakeGuard(fclose,input);
            ::Loki::ScopeGuard scopeGuard20 
            = ::Loki::MakeGuard(fclose,output);

            也就是定義2個名字以scopeGuard為前綴文件行號為后綴的“變量”(名字就不會重復)。
            它們在退出作用域的時候會分別調用:fclose(input); fclose(output);
            PS:ScopeGuard的強大還不僅僅體現在這里,以后會專門介紹。


            例2.1,內嵌匯編或者使用goto時,需要一個不重復的跳轉標號。

            make label



            例2.2,做鍵盤模擬的時候,按照i8042的規則,每次寫入端口時,需要等待輸入緩沖為空。
            所以需要實現一個 KBC_Wait4IBE (key board controller wait for input buffer empty)



            但是又不想有函數調用消耗,所以打算用宏實現。
            實驗1: 失敗的例子


            #define KBC_WAIT4IBE()  \
            KBC_WAIT4IBE_label:     \
            _asm in AL,64h      \
            _asm    TEST AL,10B \
            _asm    JNZ KBC_WAIT4IBE_label


            void KBC_KeyDown(byte scan) {
                KBC_WAIT4IBE(); // 等待輸入緩沖為空
                _outp(CMD_PORT,CMD_WRITE_OUTPUT_REG); // 準備寫入數據
                KBC_Wait4IBE(); // error C2045: 'KBC_WAIT4IBE_label' : label redefined
                // 標號重復
            }


            有一個辦法就是給標號加上行號作為后綴,那么在一個文件中也不會重復(使用 #line 除外……)。


            btw:上面那個函數實現 KBC_Wait4IBE ,在VC8 release編譯下,會直接被inline,并且生成的代碼和KBC_WAIT4IBE完全相同……
            所以,要信任編譯器的優化,不要無謂的犧牲可讀性~


            重要補充! 上述解釋并不準確!!!
            setname(var) 中的var同樣是一個宏,為什么不被替換?
            SET_NAME(VAR)的第1次替換時,同樣VAR沒有被替換,為什么第2次替換就會被替換?

            根據《代碼自動生成-宏帶來的奇技淫巧》:http://m.shnenglu.com/kevinlynx/archive/2008/03/19/44828.html
            的說法,第2次替換時,涉及一個叫prescan的機制。
            我平時對CPP研究不多,所以也沒弄明白這個機制。硬盤里專門講C的書也不多,我翻翻看有沒有詳細介紹的……

            感興趣的讀者還可以參考: http://developer.apple.com/documentation/DeveloperTools/gcc-4.0.1/cpp/Macros.html



             

            再補充一點: 關于于宏的調試。
            在MSVC下,可以給某個編譯單元xxx.c(cpp,cxx)加入"/P"(不含引號,P一定大寫)命令。
            編譯該單元后,會在xxx.c的同目錄下生成xxx.i,即預處理的結果。
            在GCC下,可以使用 gcc(g++) -E xxx.c(cpp,cxx) (必要時還需要 -i ),查看預處理結果。



            再次補充

            在《The C Programming Language》 2nd Edition中找到了解釋
            附錄A.12.3 Macro Definition and Expansion p207。
            以下只摘錄重點部分:
            During collection(指第1次), arguments are not macro-expanded.
            In both (指帶參數或者不帶參數)kinds of macro, the replacement token sequence is repeatedly rescanned for more defined identifiers.


            沒能搜到ANSI C標準的文檔……

            posted on 2009-02-18 23:59 OwnWaterloo 閱讀(3492) 評論(4)  編輯 收藏 引用

            FeedBack:
            # re: 使用宏作宏參數
            2009-02-19 09:25 | 飄雪
            好文,我原來對這個問題也想了很久  回復  更多評論
              
            # re: 使用宏作宏參數
            2009-02-19 09:52 | 路青飛
            我可不可理解為,宏中宏!
            哈哈!好文!贊一個!  回復  更多評論
              
            # re: 使用宏作宏參數
            2009-02-19 11:50 |
            不錯,終于明白這個問題了!當初困擾我很久,還是沒有解決的問題!哈哈  回復  更多評論
              
            # re: 使用宏作宏參數
            2010-05-10 17:05 | PattersonGay
            That is good that we are able to receive the <a href="http://lowest-rate-loans.com/topics/home-loans">home loans</a> and that opens new opportunities.   回復  更多評論
              
            # re: 使用宏作宏參數
            2010-08-08 14:31 | ringtone
            Any human in the our world wants to stay original, but does not know the correct way to do it. But thousands of different people look for the ringtones download or just composer ringtones to be unique.   回復  更多評論
              
            # re: 使用宏作宏參數
            2012-07-02 09:25 | on line essays
            To my mind, here only we receive the groundbreakingnewfangled brilliant data just about this good topic and that can be easygoing for men to buy term papers or buy an essay bestwritingservice.com from the professional custom essays writing firm.   回復  更多評論
              
            <2025年8月>
            272829303112
            3456789
            10111213141516
            17181920212223
            24252627282930
            31123456

            常用鏈接

            留言簿(8)

            隨筆檔案(16)

            鏈接

            搜索

            •  

            積分與排名

            • 積分 - 198659
            • 排名 - 134

            最新隨筆

            最新評論

            閱讀排行榜

            評論排行榜

            久久亚洲日韩精品一区二区三区| 激情综合色综合久久综合| 亚洲欧美日韩久久精品| 久久无码精品一区二区三区| 精品久久久久久无码中文野结衣 | 久久久久99精品成人片试看| 丰满少妇人妻久久久久久| 亚洲狠狠久久综合一区77777| 久久av高潮av无码av喷吹| 伊人久久大香线蕉综合网站| 精品伊人久久大线蕉色首页| 久久99免费视频| 久久精品视频一| 99久久国产综合精品麻豆| 亚洲欧洲精品成人久久曰影片 | 久久午夜羞羞影院免费观看| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 亚洲AV无一区二区三区久久 | 狠狠色丁香婷婷久久综合不卡| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 久久本道久久综合伊人| 无码人妻久久一区二区三区免费| 国产精品久久久久9999| 色老头网站久久网| 国产精品欧美久久久久无广告 | 久久久久波多野结衣高潮| 欧美久久综合性欧美| 无码人妻久久久一区二区三区| 久久影院亚洲一区| 99久久精品费精品国产| 久久er99热精品一区二区| 欧美伊人久久大香线蕉综合| 九九久久精品国产| 国产福利电影一区二区三区,免费久久久久久久精 | 精品久久久久久无码免费| 99久久99久久| 亚洲AV日韩精品久久久久| 久久亚洲熟女cc98cm| 婷婷国产天堂久久综合五月| 久久亚洲中文字幕精品一区四| 精品久久久久久无码免费|