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

loop_in_codes

低調(diào)做技術(shù)__歡迎移步我的獨(dú)立博客 codemaro.com 微博 kevinlynx

代碼自動生成-宏帶來的奇技淫巧

Author : Kevin Lynx

眾多C++書籍都忠告我們C語言宏是萬惡之首,但事情總不如我們想象的那么壞,就如同goto一樣。宏有
一個很大的作用,就是自動為我們產(chǎn)生代碼。如果說模板可以為我們產(chǎn)生各種型別的代碼(型別替換),
那么宏其實(shí)可以為我們在符號上產(chǎn)生新的代碼(即符號替換、增加)。

關(guān)于宏的一些語法問題,可以在google上找到。相信我,你對于宏的了解絕對沒你想象的那么多。如果你
還不知道#和##,也不知道prescan,那么你肯定對宏的了解不夠。

我稍微講解下宏的一些語法問題(說語法問題似乎不妥,macro只與preprocessor有關(guān),跟語義分析又無關(guān)):

1. 宏可以像函數(shù)一樣被定義,例如:
   #define min(x,y) (x<y?x:y) //事實(shí)上這個宏存在BUG
   但是在實(shí)際使用時,只有當(dāng)寫上min(),必須加括號,min才會被作為宏展開,否則不做任何處理。
  
2. 如果宏需要參數(shù),你可以不傳,編譯器會給你警告(宏參數(shù)不夠),但是這會導(dǎo)致錯誤。如C++書籍中所描
   述的,編譯器(預(yù)處理器)對宏的語法檢查不夠,所以更多的檢查性工作得你自己來做。

3. 很多程序員不知道的#和##
   #符號把一個符號直接轉(zhuǎn)換為字符串,例如:
   #define STRING(x) #x
   const char *str = STRING( test_string ); str的內(nèi)容就是"test_string",也就是說#會把其后的符號
   直接加上雙引號。
   ##符號會連接兩個符號,從而產(chǎn)生新的符號(詞法層次),例如:
   #define SIGN( x ) INT_##x
   int SIGN( 1 ); 宏被展開后將成為:int INT_1;

4. 變參宏,這個比較酷,它使得你可以定義類似的宏:
   #define LOG( format, ... ) printf( format, __VA_ARGS__ )
   LOG( "%s %d", str, count );
   __VA_ARGS__是系統(tǒng)預(yù)定義宏,被自動替換為參數(shù)列表。

5. 當(dāng)一個宏自己調(diào)用自己時,會發(fā)生什么?例如:
   #define TEST( x ) ( x + TEST( x ) )
   TEST( 1 ); 會發(fā)生什么?為了防止無限制遞歸展開,語法規(guī)定,當(dāng)一個宏遇到自己時,就停止展開,也就是
   說,當(dāng)對TEST( 1 )進(jìn)行展開時,展開過程中又發(fā)現(xiàn)了一個TEST,那么就將這個TEST當(dāng)作一般的符號。TEST(1)
   最終被展開為:1 + TEST( 1) 。

6. 宏參數(shù)的prescan,
   當(dāng)一個宏參數(shù)被放進(jìn)宏體時,這個宏參數(shù)會首先被全部展開(有例外,見下文)。當(dāng)展開后的宏參數(shù)被放進(jìn)宏體時,
   預(yù)處理器對新展開的宏體進(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宏里對宏參數(shù)使用了#或##,那么宏參數(shù)不會被展開:
   #define PARAM( x ) #x
   #define ADDPARAM( x ) INT_##x
   PARAM( ADDPARAM( 1 ) ); 將被展開為"ADDPARAM( 1 )"。

   使用這么一個規(guī)則,可以創(chuàng)建一個很有趣的技術(shù):打印出一個宏被展開后的樣子,這樣可以方便你分析代碼:
   #define TO_STRING( x ) TO_STRING1( x )
   #define TO_STRING1( x ) #x
   TO_STRING首先會將x全部展開(如果x也是一個宏的話),然后再傳給TO_STRING1轉(zhuǎn)換為字符串,現(xiàn)在你可以這樣:
   const char *str = TO_STRING( PARAM( ADDPARAM( 1 ) ) );去一探PARAM展開后的樣子。

7. 一個很重要的補(bǔ)充:就像我在第一點(diǎn)說的那樣,如果一個像函數(shù)的宏在使用時沒有出現(xiàn)括號,那么預(yù)處理器只是
   將這個宏作為一般的符號處理(那就是不處理)。


我們來見識一下宏是如何幫助我們自動產(chǎn)生代碼的。如我所說,宏是在符號層次產(chǎn)生代碼。我在分析Boost.Function
模塊時,因?yàn)樗褂昧舜罅康暮?宏嵌套,再嵌套),導(dǎo)致我壓根沒看明白代碼。后來發(fā)現(xiàn)了一個小型的模板庫ttl,說的
是開發(fā)一些小型組件去取代部分Boost(這是一個好理由,因?yàn)锽oost確實(shí)太大)。同樣,這個庫也包含了一個function庫。
這里的function也就是我之前提到的functor。ttl.function庫里為了自動產(chǎn)生很多類似的代碼,使用了一個宏:

#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)用方式,自動產(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)這個宏,可以看出這個宏最終產(chǎn)生的是:
typename T1
typename T1, typename T2
typename T1, typename T2, typename T3
///...
我們不妨分析TTL_TPARAMS(n)的整個過程。分析宏主要把握我以上提到的一些要點(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雖然也是兩個宏,他們被作為TTL_REPEAT宏的參數(shù),按照prescan規(guī)則,似乎應(yīng)該先將
這兩個宏展開再傳給TTL_REPEAT。但是,如同我在前面重點(diǎn)提到的,這兩個宏是function-like macro,使用時需要加括號,
如果沒加括號,則不當(dāng)作宏處理。因此,展開TTL_REPEAT時,應(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)
這個宏體看起來很復(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ù)的原則,會先展開TTL_DEC(1)
=> TTL_APPEND(TTL_CNTDEC_,1) => TTL_CNTDEC_1
#define TTL_CNTDEC_1 0  注意,TTL_CNTDEC_不是宏,TTL_CNTDEC_1是一個宏。
=> 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這個宏為空,那么,上面說的第一部分被忽略,現(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í)可以讓我們編碼更自動化。

參考資料:
macro語法: http://developer.apple.com/documentation/DeveloperTools/gcc-4.0.1/cpp/Macros.html
ttl(tiny template library) : http://tinytl.sourceforge.net/

  
 

posted on 2008-03-19 10:34 Kevin Lynx 閱讀(14432) 評論(7)  編輯 收藏 引用 所屬分類: c/c++

評論

# re: 代碼自動生成-宏帶來的奇技淫巧[未登錄] 2008-03-19 11:31 cppexplore

不錯!
c語言的程序里經(jīng)常是遍地的宏 遍地指針的精巧使用

宏還是非常不錯的 類似c語言中的模版機(jī)制
內(nèi)核里的經(jīng)典數(shù)據(jù)結(jié)構(gòu)及其算法,象SLIST LIST TAILQ之類的都是宏寫的  回復(fù)  更多評論   

# re: 代碼自動生成-宏帶來的奇技淫巧 2008-03-19 18:08 酷勤網(wǎng)

代碼編寫,不應(yīng)該過分使用“技巧” 有些看似技巧的東西,實(shí)質(zhì)沒有多大價(jià)值。  回復(fù)  更多評論   

# re: 代碼自動生成-宏帶來的奇技淫巧 2008-03-25 10:16 suxiaojack

@酷勤網(wǎng)
no,no!這根本不是技巧,是語言的形式化抽象,把很長的東西,一層層映射到短小的上去。編程要做的一部分工作也就是這個。  回復(fù)  更多評論   

# re: 代碼自動生成-宏帶來的奇技淫巧[未登錄] 2008-03-25 11:32 cppexplore

@suxiaojack
呵呵 一語中的!文中的內(nèi)容的確不是技巧,都是能優(yōu)雅解決實(shí)際問題的東東  回復(fù)  更多評論   

# re: 代碼自動生成-宏帶來的奇技淫巧 2008-05-10 10:38 zhang某人

做日志還是很爽的~~  回復(fù)  更多評論   

# re: 代碼自動生成-宏帶來的奇技淫巧 2008-12-10 12:27 秒大刀

在不會特別厭煩的一般情況下,請避免使用宏
即使是min和max也不如std::min和std::max  回復(fù)  更多評論   

# re: 代碼自動生成-宏帶來的奇技淫巧 2012-02-09 12:17 hcconquer

@秒大刀
為啥  回復(fù)  更多評論   

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲男人的天堂在线aⅴ视频| 欧美一区二区视频在线| 亚洲国内自拍| 模特精品在线| 亚洲制服丝袜在线| 欧美视频免费看| 日韩午夜电影在线观看| 欧美韩日一区| 蜜臀av性久久久久蜜臀aⅴ四虎 | 国产精品网站视频| aa成人免费视频| 亚洲破处大片| 欧美日本三区| 亚洲一区二区三区免费在线观看 | 亚洲一区中文字幕在线观看| 欧美日韩美女| 久久精品中文| 久久精品123| 国产欧美亚洲日本| 欧美一级久久| 欧美一区观看| 亚洲第一中文字幕| 欧美成人黄色小视频| 美女精品视频一区| 日韩一二三区视频| 一区二区精品国产| 国产精品主播| 女同性一区二区三区人了人一| 另类尿喷潮videofree| 亚洲精品视频在线看| 亚洲美女精品一区| 国产精品人成在线观看免费| 欧美中文字幕第一页| 久久米奇亚洲| 一本色道久久综合亚洲精品高清| 一区二区三区日韩欧美| 国产一区二区三区不卡在线观看| 欧美a级一区| 欧美日韩国产123区| 香蕉久久久久久久av网站| 欧美一区二区三区视频在线| 欧美成人免费观看| 久久久xxx| 欧美成人高清视频| 亚洲女爱视频在线| 久久免费视频在线| 亚洲视频每日更新| 久久精品理论片| 99精品视频一区| 欧美一区二区日韩一区二区| 亚洲美女电影在线| 午夜在线成人av| 99精品免费| 久久久精品午夜少妇| 亚洲先锋成人| 免费一级欧美片在线观看| 亚洲新中文字幕| 久久天天躁狠狠躁夜夜爽蜜月| 亚洲乱码国产乱码精品精天堂 | 欧美电影免费观看高清完整版| 亚洲一区二区三区激情| 久久在线播放| 久久成人免费日本黄色| 欧美激情一区二区三区成人| 久久精品72免费观看| 欧美日韩一区二区三区在线观看免| 久久久久网站| 国产麻豆成人精品| 亚洲人成网站在线播| 激情综合中文娱乐网| 国产精品国产成人国产三级| 狠狠狠色丁香婷婷综合久久五月| 一本久久综合亚洲鲁鲁| 亚洲区中文字幕| 久久久999| 久久精品官网| 国产精品揄拍500视频| 日韩一区二区福利| 久久精品综合网| 欧美国产综合| 欧美在线不卡| 午夜久久久久久久久久一区二区| 99精品福利视频| 老色鬼精品视频在线观看播放 | 91久久久一线二线三线品牌| 亚洲免费一级电影| 亚洲一区二区三区高清| 欧美日韩免费| 日韩亚洲一区二区| 在线亚洲电影| 欧美日韩一区二区在线视频| 亚洲国产精品黑人久久久| 亚洲国产成人在线| 老司机67194精品线观看| 蜜桃av综合| 1000部精品久久久久久久久| 久久裸体视频| 欧美成人午夜激情在线| 亚洲高清视频中文字幕| 乱中年女人伦av一区二区| 午夜欧美精品| 欧美四级在线观看| 亚洲在线一区二区| 久久精品99无色码中文字幕| 国模套图日韩精品一区二区| 久久久久久午夜| 亚洲高清视频一区| 亚洲伦伦在线| 欧美午夜性色大片在线观看| 亚洲一级片在线观看| 久久国产欧美日韩精品| 在线电影国产精品| 欧美精选一区| 在线一区免费观看| 久久国产精品一区二区| …久久精品99久久香蕉国产| 欧美人妖另类| 欧美一区二区三区免费大片| 欧美a级大片| 亚洲女同在线| 经典三级久久| 欧美三级不卡| 久久精品视频在线播放| 欧美高清视频在线| 亚洲最新在线视频| 国产欧美一二三区| 欧美a级理论片| 亚洲网站视频福利| 玖玖国产精品视频| 日韩天堂av| 国产午夜精品久久久| 美日韩精品视频免费看| 亚洲一级免费视频| 亚洲国产激情| 久久这里有精品视频| 怡红院av一区二区三区| 欧美日韩亚洲激情| 久久精品国产99国产精品澳门| 欧美激情国产精品| 欧美影院午夜播放| 一区二区精品在线| 国内免费精品永久在线视频| 欧美三级在线视频| 老司机免费视频一区二区三区| 亚洲一级黄色片| 欧美激情 亚洲a∨综合| 国产精品99久久久久久久vr | 免费日韩一区二区| 在线亚洲高清视频| 亚洲国产日韩在线| 国产日韩一区二区三区| 欧美不卡高清| 久久精品在线| 亚洲一区二区三区精品动漫| 亚洲级视频在线观看免费1级| 久久成人免费网| 亚洲欧美日本伦理| 亚洲特级毛片| 99精品热6080yy久久| 亚洲国产精品va| 国产综合精品一区| 国产伦精品一区二区三区在线观看| 欧美精品日韩| 欧美韩日一区二区| 你懂的成人av| 美日韩精品免费观看视频| 久久精品国产2020观看福利| 亚洲第一精品夜夜躁人人躁 | 欧美中文在线观看国产| 亚洲深夜影院| 亚洲靠逼com| 毛片基地黄久久久久久天堂| 欧美在线视频观看免费网站| 午夜精品av| 亚洲免费在线精品一区| 亚洲婷婷在线| 亚洲免费在线看| 亚洲男人的天堂在线aⅴ视频| 国产精品99久久久久久人| 亚洲视频高清| 性欧美大战久久久久久久免费观看| 亚洲综合日韩| 久久se精品一区精品二区| 久久精品国产亚洲精品| 久久精品国产91精品亚洲| 久久久久国产一区二区| 久久五月激情| 欧美国产日韩亚洲一区| 亚洲黄色成人网| 亚洲精品国产品国语在线app | 国产九九视频一区二区三区| 国产精品专区一| 国产主播在线一区| 在线精品亚洲一区二区| 亚洲日本va午夜在线影院| 亚洲全部视频| 亚洲欧美国产精品桃花| 久久精品人人做人人爽电影蜜月| 欧美在线首页| 美女在线一区二区|