青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

關(guān)于宏的一些技巧,總結(jié)得挺好,寫庫(kù)的時(shí)候比較有用。
轉(zhuǎn)自http://m.shnenglu.com/kevinlynx/archive/2008/03/19/44828.html
眾多C++書籍都忠告我們C語言宏是萬惡之首,但事情總不如我們想象的那么壞,就如同goto一樣。宏有
一個(gè)很大的作用,就是自動(dòng)為我們產(chǎn)生代碼。如果說模板可以為我們產(chǎn)生各種型別的代碼(型別替換),
那么宏其實(shí)可以為我們?cè)诜?hào)上產(chǎn)生新的代碼(即符號(hào)替換、增加)。
關(guān)于宏的一些語法問題,可以在google上找到。相信我,你對(duì)于宏的了解絕對(duì)沒你想象的那么多。如果你
還不知道#和##,也不知道prescan,那么你肯定對(duì)宏的了解不夠。
我稍微講解下宏的一些語法問題(說語法問題似乎不妥,macro只與preprocessor有關(guān),跟語義分析又無關(guān)):
1. 宏可以像函數(shù)一樣被定義,例如:
   #define min(x,y) (x<y?x:y) //事實(shí)上這個(gè)宏存在BUG
   但是在實(shí)際使用時(shí),只有當(dāng)寫上min(),必須加括號(hào),min才會(huì)被作為宏展開,否則不做任何處理。
   
2. 如果宏需要參數(shù),你可以不傳,編譯器會(huì)給你警告(宏參數(shù)不夠),但是這會(huì)導(dǎo)致錯(cuò)誤。如C++書籍中所描
   述的,編譯器(預(yù)處理器)對(duì)宏的語法檢查不夠,所以更多的檢查性工作得你自己來做。
3. 很多程序員不知道的#和##
   #符號(hào)把一個(gè)符號(hào)直接轉(zhuǎn)換為字符串,例如:
   #define STRING(x) #x
   const char *str = STRING( test_string ); str的內(nèi)容就是"test_string",也就是說#會(huì)把其后的符號(hào)
   直接加上雙引號(hào)。
   ##符號(hào)會(huì)連接兩個(gè)符號(hào),從而產(chǎn)生新的符號(hào)(詞法層次),例如:
   #define SIGN( x ) INT_##x
   int SIGN( 1 ); 宏被展開后將成為:int INT_1;

   但有小問題要注意,宏中遇到#或##時(shí)就不會(huì)再展開宏中嵌套的宏了。什么意思了?比如使用char *pChar = STRING(__FILE__);雖然__FILE__本身也是一個(gè)宏,但編譯器不會(huì)展開它,所以pChar將指向"__FILE__"而不是你要想的形如"D:\XXX.cpp"的源文件名稱。因此要加一個(gè)中間轉(zhuǎn)換宏,先將__FILE__解析成"D:\XXX.cpp"字符串。
定義如下所示二個(gè)宏:
#define _STRING(x) #x
#define STRING(x) _STRING(x)
再調(diào)用下面語句將輸出帶""的源文件路徑
       char* pChar = STRING(__FILE__);
       printf("%s %s\n", pChar, __FILE__);
可以比較下STRING(__FILE__)與__FILE__的不同,前將帶雙引號(hào),后一個(gè)沒有雙引號(hào)。

4. 變參宏,這個(gè)比較酷,它使得你可以定義類似的宏:
   #define LOG( format, ... ) printf( format, __VA_ARGS__ )
   LOG( "%s %d", str, count );
   __VA_ARGS__是系統(tǒng)預(yù)定義宏,被自動(dòng)替換為參數(shù)列表。
5. 當(dāng)一個(gè)宏自己調(diào)用自己時(shí),會(huì)發(fā)生什么?例如:
   #define TEST( x ) ( x + TEST( x ) )
   TEST( 1 ); 會(huì)發(fā)生什么?為了防止無限制遞歸展開,語法規(guī)定,當(dāng)一個(gè)宏遇到自己時(shí),就停止展開,也就是
   說,當(dāng)對(duì)TEST( 1 )進(jìn)行展開時(shí),展開過程中又發(fā)現(xiàn)了一個(gè)TEST,那么就將這個(gè)TEST當(dāng)作一般的符號(hào)。TEST(1)
   最終被展開為:1 + TEST( 1) 。
6. 宏參數(shù)的prescan,
   當(dāng)一個(gè)宏參數(shù)被放進(jìn)宏體時(shí),這個(gè)宏參數(shù)會(huì)首先被全部展開(有例外,見下文)。當(dāng)展開后的宏參數(shù)被放進(jìn)宏體時(shí),
   預(yù)處理器對(duì)新展開的宏體進(jìn)行第二次掃描,并繼續(xù)展開。例如:
   #define PARAM( x ) x
   #define ADDPARAM( x ) INT_##x
   PARAM( ADDPARAM( 1 ) ); 
   因?yàn)锳DDPARAM( 1 ) 是作為PARAM的宏參數(shù),所以先將ADDPARAM( 1 )展開為INT_1,然后再將INT_1放進(jìn)PARAM。
   
   例外情況是,如果PARAM宏里對(duì)宏參數(shù)使用了#或##,那么宏參數(shù)不會(huì)被展開:
   #define PARAM( x ) #x
   #define ADDPARAM( x ) INT_##x
   PARAM( ADDPARAM( 1 ) ); 將被展開為"ADDPARAM( 1 )"。
   使用這么一個(gè)規(guī)則,可以創(chuàng)建一個(gè)很有趣的技術(shù):打印出一個(gè)宏被展開后的樣子,這樣可以方便你分析代碼:
   #define TO_STRING( x ) TO_STRING1( x )
   #define TO_STRING1( x ) #x
   TO_STRING首先會(huì)將x全部展開(如果x也是一個(gè)宏的話),然后再傳給TO_STRING1轉(zhuǎn)換為字符串,現(xiàn)在你可以這樣:
   const char *str = TO_STRING( PARAM( ADDPARAM( 1 ) ) );去一探PARAM展開后的樣子。
7. 一個(gè)很重要的補(bǔ)充:就像我在第一點(diǎn)說的那樣,如果一個(gè)像函數(shù)的宏在使用時(shí)沒有出現(xiàn)括號(hào),那么預(yù)處理器只是
   將這個(gè)宏作為一般的符號(hào)處理(那就是不處理)。
我們來見識(shí)一下宏是如何幫助我們自動(dòng)產(chǎn)生代碼的。如我所說,宏是在符號(hào)層次產(chǎn)生代碼。我在分析Boost.Function
模塊時(shí),因?yàn)樗褂昧舜罅康暮?宏嵌套,再嵌套),導(dǎo)致我壓根沒看明白代碼。后來發(fā)現(xiàn)了一個(gè)小型的模板庫(kù)ttl,說的
是開發(fā)一些小型組件去取代部分Boost(這是一個(gè)好理由,因?yàn)锽oost確實(shí)太大)。同樣,這個(gè)庫(kù)也包含了一個(gè)function庫(kù)。
這里的function也就是我之前提到的functor。ttl.function庫(kù)里為了自動(dòng)產(chǎn)生很多類似的代碼,使用了一個(gè)宏:
#define TTL_FUNC_BUILD_FUNCTOR_CALLER(n)  \
 template< typename R, TTL_TPARAMS(n) > \
 struct functor_caller_base##n \
        ///...
該宏的最終目的是:通過類似于TTL_FUNC_BUILD_FUNCTOR_CALLER(1)的調(diào)用方式,自動(dòng)產(chǎn)生很多functor_caller_base模板:
template <typename R, typename T1> struct functor_caller_base1
template <typename R, typename T1, typename T2> struct functor_caller_base2
template <typename R, typename T1, typename T2, typename T3> struct functor_caller_base3
///... 
那么,核心部分在于TTL_TPARAMS(n)這個(gè)宏,可以看出這個(gè)宏最終產(chǎn)生的是:
typename T1
typename T1, typename T2
typename T1, typename T2, typename T3
///...
我們不妨分析TTL_TPARAMS(n)的整個(gè)過程。分析宏主要把握我以上提到的一些要點(diǎn)即可。以下過程我建議你翻著ttl的代碼,
相關(guān)代碼文件:function.hpp, macro_params.hpp, macro_repeat.hpp, macro_misc.hpp, macro_counter.hpp。
so, here we go
分析過程,逐層分析,逐層展開,例如TTL_TPARAMS(1):
#define TTL_TPARAMS(n) TTL_TPARAMSX(n,T)  
=> TTL_TPARAMSX( 1, T )
#define TTL_TPARAMSX(n,t) TTL_REPEAT(n, TTL_TPARAM, TTL_TPARAM_END, t)
=> TTL_REPEAT( 1, TTL_TPARAM, TTL_TPARAM_END, T )
#define TTL_TPARAM(n,t) typename t##n, 
#define TTL_TPARAM_END(n,t) typename t##n
#define TTL_REPEAT(n, m, l, p) TTL_APPEND(TTL_REPEAT_, TTL_DEC(n))(m,l,p) TTL_APPEND(TTL_LAST_REPEAT_,n)(l,p)
注意,TTL_TPARAM, TTL_TPARAM_END雖然也是兩個(gè)宏,他們被作為TTL_REPEAT宏的參數(shù),按照prescan規(guī)則,似乎應(yīng)該先將
這兩個(gè)宏展開再傳給TTL_REPEAT。但是,如同我在前面重點(diǎn)提到的,這兩個(gè)宏是function-like macro,使用時(shí)需要加括號(hào),
如果沒加括號(hào),則不當(dāng)作宏處理。因此,展開TTL_REPEAT時(shí),應(yīng)該為:
=> TTL_APPEND( TTL_REPEAT_, TTL_DEC(1))(TTL_TPARAM,TTL_TPARAM_END,T) TTL_APPEND( TTL_LAST_REPEAT_,1)(
TTL_TPARAM_END,T)
這個(gè)宏體看起來很復(fù)雜,仔細(xì)分析下,可以分為兩部分:
TTL_APPEND( TTL_REPEAT_, TTL_DEC(1))(TTL_TPARAM,TTL_TPARAM_END,T)以及
TTL_APPEND( TTL_LAST_REPEAT_,1)(TTL_TPARAM_END,T)
先分析第一部分:
#define TTL_APPEND( x, y ) TTL_APPEND1(x,y) //先展開x,y再將x,y連接起來
#define TTL_APPEND1( x, y ) x ## y
#define TTL_DEC(n) TTL_APPEND(TTL_CNTDEC_, n)
根據(jù)先展開參數(shù)的原則,會(huì)先展開TTL_DEC(1)
=> TTL_APPEND(TTL_CNTDEC_,1) => TTL_CNTDEC_1 
#define TTL_CNTDEC_1 0  注意,TTL_CNTDEC_不是宏,TTL_CNTDEC_1是一個(gè)宏。
=> 0 , 也就是說,TTL_DEC(1)最終被展開為0。回到TTL_APPEND部分:
=> TTL_REPEAT_0 (TTL_TPARAM,TTL_TPARAM_END,T) 
#define TTL_REPEAT_0(m,l,p)
TTL_REPEAT_0這個(gè)宏為空,那么,上面說的第一部分被忽略,現(xiàn)在只剩下第二部分:
TTL_APPEND( TTL_LAST_REPEAT_,1)(TTL_TPARAM_END,T)
=> TTL_LAST_REPEAT_1 (TTL_TPARAM_END,T) // TTL_APPEND將TTL_LAST_REPEAT_和1合并起來
#define TTL_LAST_REPEAT_1(m,p) m(1,p)
=> TTL_TPARAM_END( 1, T )
#define TTL_TPARAM_END(n,t) typename t##n
=> typename T1  展開完畢。
雖然我們分析出來了,但是這其實(shí)并不是我們想要的。我們應(yīng)該從那些宏里去獲取作者關(guān)于宏的編程思想。很好地使用宏
看上去似乎是一些偏門的奇技淫巧,但是他確實(shí)可以讓我們編碼更自動(dòng)化。
參考資料:
macro語法: http://developer.apple.com/documentation/DeveloperTools/gcc-4.0.1/cpp/Macros.html
ttl(tiny template library) : http://tinytl.sourceforge.net/
posted on 2013-03-25 17:31 Richard Wei 閱讀(1872) 評(píng)論(0)  編輯 收藏 引用 所屬分類: C++
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            农村妇女精品| 国产精品手机视频| 亚洲激情视频| 欧美高清视频一区二区| 欧美ed2k| 一本大道久久精品懂色aⅴ| 亚洲精品在线看| 国产精品乱看| 久久国产一区| 久久天天狠狠| 一本色道久久综合狠狠躁篇怎么玩| 亚洲电影免费观看高清完整版在线观看 | 亚洲欧美日韩在线不卡| 亚洲欧美日韩天堂一区二区| 国产一区二区精品久久| 亚洲成人在线视频播放| 欧美日韩视频在线一区二区 | 亚洲欧洲美洲综合色网| 亚洲激情另类| 国产欧美一区二区精品性色| 女人色偷偷aa久久天堂| 欧美日韩黄色大片| 久久久久久久综合| 欧美精品免费在线观看| 香蕉尹人综合在线观看| 美女视频网站黄色亚洲| 亚洲与欧洲av电影| 另类综合日韩欧美亚洲| 亚洲影视在线| 美女国内精品自产拍在线播放| 亚洲一区二区三区午夜| 午夜精品区一区二区三| 日韩亚洲欧美在线观看| 欧美中文在线观看| 亚洲视频碰碰| 久久免费视频网站| 性欧美大战久久久久久久久| 玖玖综合伊人| 欧美一区二区三区在线观看视频| 欧美成人精品激情在线观看| 欧美一区二区三区四区在线观看地址| 欧美88av| 麻豆精品一区二区av白丝在线| 欧美日韩免费观看一区三区| 久久亚洲精品欧美| 国产欧美短视频| 99亚洲一区二区| 亚洲久久视频| 久久久久久欧美| 欧美一级免费视频| 国产精品第一页第二页第三页| 欧美激情视频一区二区三区免费 | 欧美日本精品| 亚洲国产精品成人久久综合一区 | 欧美成人国产| 免费成人在线观看视频| 国产日韩在线播放| 亚洲资源av| 午夜精品国产精品大乳美女| 欧美精品一卡| 亚洲日本无吗高清不卡| 亚洲国产日韩一区二区| 久久亚洲私人国产精品va媚药| 久久国产99| 国产日韩欧美在线看| 亚洲一区二区免费在线| 午夜精品www| 国产精品日日做人人爱 | 欧美一区二区在线看| 国产精品久久夜| 中文精品视频| 午夜久久久久久| 国产伦精品一区二区| 亚洲欧美日韩国产综合在线| 亚洲欧美日韩精品久久奇米色影视| 欧美色图首页| 亚洲无线一线二线三线区别av| 亚洲欧美日韩在线播放| 国产精品免费视频观看| 午夜国产精品影院在线观看 | 亚洲精选91| 欧美日韩一区高清| 亚洲主播在线| 裸体一区二区三区| 亚洲日本免费| 欧美午夜电影一区| 欧美一区二视频| 美女任你摸久久| 日韩视频在线一区| 国产精品sm| 久久久91精品国产| 亚洲经典三级| 香蕉成人久久| 亚洲福利在线观看| 欧美香蕉视频| 久久成人综合网| 亚洲人成网站影音先锋播放| 亚洲在线黄色| 在线免费高清一区二区三区| 欧美日韩国产色站一区二区三区| 亚洲一二区在线| 女同性一区二区三区人了人一 | 国产日韩一区欧美| 欧美电影免费观看网站| 亚洲午夜视频在线观看| 欧美成人日本| 欧美一区二区三区视频免费| 91久久精品美女高潮| 国产精品萝li| 欧美波霸影院| 欧美在线视频一区| 亚洲乱码久久| 蜜桃av噜噜一区二区三区| 亚洲午夜电影| 亚洲高清影视| 国产一区欧美日韩| 欧美体内谢she精2性欧美| 久久天天躁夜夜躁狠狠躁2022| 国产精品99久久久久久久久久久久| 久久夜色精品国产亚洲aⅴ | 亚洲高清久久久| 国产精品视频精品视频| 欧美激情bt| 久久久久久久久岛国免费| 亚洲专区欧美专区| 99爱精品视频| 亚洲精品九九| 欧美成人免费网站| 美日韩精品免费| 欧美影片第一页| 午夜精品久久久久久99热软件| 日韩一区二区精品葵司在线| 精品999网站| 国产一区二区三区精品欧美日韩一区二区三区| 欧美日韩第一页| 欧美成人四级电影| 蜜桃av一区二区| 久久亚洲私人国产精品va| 性8sex亚洲区入口| 午夜精品久久久99热福利| 亚洲性图久久| 亚洲一级在线观看| 亚洲网站在线看| 中文av一区特黄| 亚洲在线免费观看| 午夜一区二区三区在线观看| 亚洲在线黄色| 午夜一区二区三区不卡视频| 亚洲欧美另类综合偷拍| 亚洲欧美日韩国产综合| 午夜精品久久久久久久99黑人| 亚洲欧美日本日韩| 亚洲欧美中文字幕| 久久er99精品| 久久蜜桃香蕉精品一区二区三区| 久久婷婷丁香| 欧美激情成人在线视频| 欧美日韩免费高清一区色橹橹| 欧美母乳在线| 国产精品国产自产拍高清av| 国产精品青草综合久久久久99| 国产女优一区| 在线观看欧美日本| 日韩视频在线永久播放| 亚洲一区激情| 久久成人精品视频| 麻豆免费精品视频| 亚洲精品永久免费| 亚洲女优在线| 麻豆精品在线播放| 国产精品v欧美精品v日韩 | 国产精品二区二区三区| 国产精品一区二区欧美| 黄色一区二区三区四区| 日韩网站免费观看| 欧美一区二区三区日韩| 欧美xxx成人| 一区二区三区高清在线观看| 久久成年人视频| 欧美日韩a区| 国产资源精品在线观看| 一本色道久久88综合日韩精品 | 亚洲国产福利在线| 亚洲视频 欧洲视频| 久久久精品动漫| 亚洲乱码国产乱码精品精| 欧美一区二区黄色| 欧美日本国产一区| 很黄很黄激情成人| 亚洲网站在线| 欧美激情一区二区久久久| 亚洲永久免费观看| 欧美mv日韩mv国产网站| 国产日韩在线一区| 日韩视频在线一区| 麻豆国产va免费精品高清在线| 一本色道久久综合精品竹菊 | 一区二区三区三区在线| 久久免费国产精品1| 国产伦精品一区二区三区免费|