• <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>

            woaidongmao

            文章均收錄自他人博客,但不喜標(biāo)題前加-[轉(zhuǎn)貼],因其丑陋,見諒!~
            隨筆 - 1469, 文章 - 0, 評論 - 661, 引用 - 0
            數(shù)據(jù)加載中……

            VC中一個關(guān)于宏的使用問題

            這兒是個關(guān)于宏的問題,我曾用過ATL的串轉(zhuǎn)換宏,包括W2A,開始有些東西我還不太明白。為了使用這些宏,必須在函數(shù)的開始處用USES_CONVERSION來初始化某些局部變量。用就用吧,但是看看這個宏的定義,它有類似下面的代碼:

            // atlconv.h文件中
            #define USES_CONVERSION \
            int _convert; _convert; \
            UINT _acp = GetACP(); _acp; \
            LPCWSTR _lpw; _lpw; \?
            LPCSTR _lpa; _lpa

            為什么它們用“int x;x;”——這種后面跟著變量的聲明? 

               
            很多人都碰到過這個令人困惑的問題,后來發(fā)現(xiàn)答案很簡單:禁止編譯器的警告信息(warning)。如果單獨(dú)有一行代碼:
            int x;
            且從來沒有使用過x,那么編譯器匯報錯“unreferenced local variablex”,意思是未引用過的局部變量x,如果將警告信息的輸出調(diào)到最大。為了避免討厭的警告,USES_CONVERSION引用聲明的變量。

                  int x; // 聲明
                  x;     //
            使用這個變量
                 

            C++之前的時代,程序員有時在C中用函數(shù)形參做同樣的事情來避免“unreferenced formal parameter”或其它的深奧費(fèi)解的編譯錯誤。

            void MyFunc(int x, char y)
            {
              x;
              y;
              ......
            }

            當(dāng)然,現(xiàn)在用下面的代碼可以更有效地完成同樣的事情:

            // 參數(shù) x 不是用
            void MyFunc(int /* x */)
            {
               ......
            }    

                也就是說聲明參數(shù),但不給它起名,不能這樣使用局部變量;必須顯式地引用它。這樣做不會增加任何指令到代碼中。最多可能多增加幾個字節(jié)到堆棧(為x預(yù)留空 間)。靈巧的編譯器甚至不會操心x從來沒有被使用過——雖然好奇心可能想知道:如果編譯器夠厲害,知道了從沒有使用x,為什么要抱怨(編譯出錯)呢?答案是因?yàn)榭量痰某绦騿T(且編程能力與個人的記性有關(guān))使用編譯警告提醒自己刪除某部分代碼時發(fā)生變量荒廢。這種警告在C時代很有用,你必須在每個函數(shù)的頂部聲明變量,這就遠(yuǎn)離了實(shí)用它們的代碼。
               
            現(xiàn)在來看看另一個問題:為什么在開始位置要用USES_CONVERSION?即為什么W2A&Co之類的宏還需要另外的宏聲明自己的變量;為什么不直接在W2A中聲明這個變量?

            #define W2A(x) \
            int _convert; _convert; \
            ……etc

            很明顯這樣做不行,因?yàn)槿绻闶褂?span lang="EN-US">W2A兩次,得到一個復(fù)制的變量。那為什么不把整個宏放進(jìn)花括弧創(chuàng)建新的范圍?

            #define W2A(x) Q{ \
            int _convert; _convert; \
            …… \
            }

            這樣解決了命名沖突,但不能進(jìn)行如下編碼:
            DoSomething(W2A(pwstr));
            沒有辦法從代碼塊返回值,所以不能在函數(shù)調(diào)用中傳遞W2A。真笨啊,那么內(nèi)聯(lián)函數(shù)怎么樣?

            inline LPCSTR W2A(LPWSTR w) {
            int_convert;
            ……
            }

                這解決了范圍問題——任何W2A需要的變量多可以在這個函數(shù)中,在自己的范圍內(nèi)聲明,不需要另外的宏。它也提供了一種返回值的方式,使你可以在函數(shù)調(diào)用和賦值中使用W2Ax)。但是這種方法不靈,也是因?yàn)?span lang="EN-US">W2A的緣故和其它的宏更復(fù)雜。
            不管什么時候進(jìn)行Unicode轉(zhuǎn)換,都不能就地轉(zhuǎn)換串,必須分配一個臨時串容納被轉(zhuǎn)換的字節(jié)。典型地,通過調(diào)用new分配一個串:

            int len = MultiByteToWideChar(...,?
            mystr, NULL, 0); //
            或的長度
            LPWSTR p = new WCHAR[nLen]; //
            分配內(nèi)存
            MultiByteToWideChar(...,p,len); //
            轉(zhuǎn)換
            SomeCOMFunction(p); //
            使用之
            delete [] p; //
            銷毀

                這段代碼不僅令人討厭,而且還沒有效率;必須調(diào)用MultiByteToWideChar兩次(一次是計算長度,一次是實(shí)際的轉(zhuǎn)換),你得從堆中分配p, 這樣很慢。通過分配2*len個字節(jié)解決第一個問題,這里長度lenASCII串的長度——但第二個問題怎么辦?如果看看A2W是如何展開的,請看:

            // 簡化版
            #define A2W(s) \
            _len = 2*strlen(s);
            AfxA2WHelper((LPWSTR)alloca(_len);

                AfxA2Whelper是一個調(diào)用MultiByteToWideChar的輔助函數(shù)。A2W使用2*len巧妙地避免了兩次調(diào)用 MultiByteToWideChar。但A2W及其它轉(zhuǎn)換宏真正聰明的地方是不調(diào)用new操作分配臨時串,而是調(diào)用alloca——在棧中分配字節(jié), 而不是在堆中。這樣做非常快,因?yàn)榫幾g器要做的只是增加棧指針。不調(diào)用函數(shù),不處理內(nèi)存塊。它也避免了內(nèi)存碎片,并且也沒有必要調(diào)用delete操作,因 為當(dāng)控制離開alloca被調(diào)用的地址后,內(nèi)存被自動釋放。這正好說明了為什么A2W不能時內(nèi)聯(lián)函數(shù);如果是的話,alloca創(chuàng)建的臨時串會在返回前被 摧毀,并且你會以刪除串的方式終止SomeCOMFunction(使用這個例子)調(diào)用。
            A2W
            必須從alloca被調(diào)用的相同的地址處調(diào)用alloca——所以A2W必須是一個宏,不是一個函數(shù);因此它需要另一個宏 USERS_CONVERSION來聲明_len以及其它一些用到的變量(為了簡化,我省略了)。當(dāng)你仔細(xì)想想,整個處理告訴我們要想寫一組類似A2W的 宏從棧中的分配內(nèi)存會減少很多不必要的麻煩。
            另外,任何時候,只要你想要快速地獲取臨時內(nèi)存,都可以調(diào)用alloca。下面的代碼是我們常常見到的:

            char* p = new char[len];
            DoSomething(p);
            delete [] p;

            使用下面的代碼替代之會效率更高:

            char *p = (char*)alloca(len);
            DoSomething(p);
            //
            不用調(diào)用delete p!

                當(dāng)然,如果棧中的沒那么多,你還這么做的話,就會出現(xiàn)一個討厭的消息框。這個方法還有一些局限,詳細(xì)內(nèi)容請參考文檔。經(jīng)驗(yàn)告訴我,不管什么時候在MFCATL或其它什么地方發(fā)現(xiàn)奇怪的事情,最好是鉆進(jìn)去研究一下,你可能會發(fā)現(xiàn)有用的東西。

            posted on 2010-07-10 02:05 肥仔 閱讀(379) 評論(0)  編輯 收藏 引用 所屬分類: MFC存檔

            亚洲第一永久AV网站久久精品男人的天堂AV | 四虎影视久久久免费| 久久亚洲私人国产精品vA| 久久性生大片免费观看性| 久久精品国产亚洲一区二区三区| 99热精品久久只有精品| 老司机国内精品久久久久| 天天久久狠狠色综合| 国产精品久久久久久久久| 中文字幕一区二区三区久久网站| 性做久久久久久免费观看| 欧洲性大片xxxxx久久久| 久久国产成人午夜aⅴ影院 | 久久综合国产乱子伦精品免费| 中文字幕精品久久久久人妻| 久久久亚洲裙底偷窥综合| 亚洲va国产va天堂va久久| 97超级碰碰碰碰久久久久| 亚洲国产精品人久久| 久久av免费天堂小草播放| 国内精品伊人久久久久网站| 久久精品国产第一区二区| 中文字幕无码av激情不卡久久| 免费无码国产欧美久久18| 国产99久久久国产精免费| 久久婷婷人人澡人人| 久久人人爽人人爽人人片AV不| 久久久亚洲裙底偷窥综合| 久久精品国产免费一区| 精品久久久久久中文字幕大豆网| 亚洲综合精品香蕉久久网| 午夜视频久久久久一区 | 久久精品国产精品亚洲人人| 国产香蕉久久精品综合网| 看久久久久久a级毛片| 久久精品九九亚洲精品天堂| 午夜精品久久久内射近拍高清| 久久婷婷五月综合色奶水99啪| 久久不见久久见免费影院www日本| 免费无码国产欧美久久18| 亚洲国产精品久久66|