亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C++ > 正文

C/C++ 宏詳細解析

2020-01-26 15:51:57
字體:
來源:轉載
供稿:網友

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

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

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

1. 宏可以像函數一樣被定義,例如:
#define min(x,y) (x 但是在實際使用時,只有當寫上min(),必須加括號,min才會被作為宏展開,否則不做任何處理。

2. 如果宏需要參數,你可以不傳,編譯器會給你警告(宏參數不夠),但是這會導致錯誤。如C++書籍中所描述的,編譯器(預處理器)對宏的語法檢查不夠,所以更多的檢查性工作得你自己來做。

3. 很多程序員不知道的#和##
#符號把一個符號直接轉換為字符串,例如:
#define STRING(x) #x
const char *str = STRING( test_string ); str的內容就是"test_string",也就是說#會把其后的符號直接加上雙引號。
##符號會連接兩個符號,從而產生新的符號(詞法層次),例如:
#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__是系統預定義宏,被自動替換為參數列表。

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

6. 宏參數的prescan,當一個宏參數被放進宏體時,這個宏參數會首先被全部展開(有例外,見下文)。當展開后的宏參數被放進宏體時,預處理器對新展開的宏體進行第二次掃描,并繼續展開。例如:
#define PARAM( x ) x
#define ADDPARAM( x ) INT_##x
PARAM( ADDPARAM( 1 ) );
因為ADDPARAM( 1 ) 是作為PARAM的宏參數,所以先將ADDPARAM( 1 )展開為INT_1,然后再將INT_1放進PARAM。

例外情況是,如果PARAM宏里對宏參數使用了#或##,那么宏參數不會被展開:
#define PARAM( x ) #x
#define ADDPARAM( x ) INT_##x
PARAM( ADDPARAM( 1 ) ); 將被展開為"ADDPARAM( 1 )"。

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

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

我們來見識一下宏是如何幫助我們自動產生代碼的。如我所說,宏是在符號層次產生代碼。我在分析Boost.Function模塊時,因為它使用了大量的宏(宏嵌套,再嵌套),導致我壓根沒看明白代碼。后來發現了一個小型的模板庫ttl,說的是開發一些小型組件去取代部分Boost(這是一個好理由,因為Boost確實太大)。同樣,這個庫也包含了一個function庫。

這里的function也就是我之前提到的functor。ttl.function庫里為了自動產生很多類似的代碼,使用了一個宏:

#define TTL_FUNC_BUILD_FUNCTOR_CALLER(n) /
template< typename R, TTL_TPARAMS(n) > /
struct functor_caller_base##n /
///...
該宏的最終目的是:通過類似于TTL_FUNC_BUILD_FUNCTOR_CALLER(1)的調用方式,自動產生很多functor_caller_base模板:
template struct functor_caller_base1
template struct functor_caller_base2
template struct functor_caller_base3
///...
那么,核心部分在于TTL_TPARAMS(n)這個宏,可以看出這個宏最終產生的是:
typename T1
typename T1, typename T2
typename T1, typename T2, typename T3
///...
我們不妨分析TTL_TPARAMS(n)的整個過程。分析宏主要把握我以上提到的一些要點即可。以下過程我建議你翻著ttl的代碼,
相關代碼文件: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宏的參數,按照prescan規則,似乎應該先將這兩個宏展開再傳給TTL_REPEAT。但是,如同我在前面重點提到的,這兩個宏是function-like macro,使用時需要加括號,如果沒加括號,則不當作宏處理。因此,展開TTL_REPEAT時,應該為:
=> TTL_APPEND( TTL_REPEAT_, TTL_DEC(1))(TTL_TPARAM,TTL_TPARAM_END,T) TTL_APPEND( TTL_LAST_REPEAT_,1)(
TTL_TPARAM_END,T)

這個宏體看起來很復雜,仔細分析下,可以分為兩部分:
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)

根據先展開參數的原則,會先展開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?;氐絋TL_APPEND部分:
=> TTL_REPEAT_0 (TTL_TPARAM,TTL_TPARAM_END,T)
#define TTL_REPEAT_0(m,l,p)

TTL_REPEAT_0這個宏為空,那么,上面說的第一部分被忽略,現在只剩下第二部分:
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 展開完畢。

雖然我們分析出來了,但是這其實并不是我們想要的。我們應該從那些宏里去獲取作者關于宏的編程思想。很好地使用宏看上去似乎是一些偏門的奇技淫巧,但是他確實可以讓我們編碼更自動化。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美成人第一页| 日本aⅴ大伊香蕉精品视频| 日韩精品有码在线观看| 亚洲欧洲在线观看| 91精品国产综合久久香蕉最新版| 国产v综合v亚洲欧美久久| 亚洲激情电影中文字幕| 亚洲第一页中文字幕| 奇米四色中文综合久久| 亚洲国产美女久久久久| 国产一区二区色| 久久中文精品视频| 国产日韩中文字幕在线| 欧美日本在线视频中文字字幕| 欧美性69xxxx肥| 97国产在线视频| 96pao国产成视频永久免费| 国产精品久久久久久搜索| 国产va免费精品高清在线| 成人精品网站在线观看| 欧美日韩国产激情| 久久五月天综合| 91情侣偷在线精品国产| 中文字幕久热精品在线视频| 亚洲精品成人久久久| 色婷婷综合久久久久中文字幕1| 国产一区二区黑人欧美xxxx| 成人网在线免费观看| 日本国产一区二区三区| 亚洲毛片在线观看.| 欧洲美女7788成人免费视频| 国产欧美亚洲精品| 国产午夜精品全部视频播放| 色婷婷**av毛片一区| 26uuu另类亚洲欧美日本老年| 45www国产精品网站| 中文字幕综合一区| 午夜精品久久久99热福利| 在线看国产精品| 久久天天躁狠狠躁夜夜躁2014| 久久99精品视频一区97| 国产成人精品999| 欧美成aaa人片免费看| 少妇高潮久久久久久潘金莲| 91精品综合久久久久久五月天| 久久久精品2019中文字幕神马| 久久精品在线视频| 中文字幕亚洲综合久久| 亚洲日本成人女熟在线观看| 国产99视频在线观看| 日韩三级成人av网| 久久精品国产欧美亚洲人人爽| 欧美与黑人午夜性猛交久久久| 国产精品欧美日韩一区二区| 欧美激情aaaa| 美女福利精品视频| 亚洲欧洲免费视频| 欧美性xxxxx极品| 亚洲欧美另类国产| 丁香五六月婷婷久久激情| 亚洲欧洲日产国产网站| 久久精品一区中文字幕| 亚洲国产一区二区三区四区| 欧美乱大交做爰xxxⅹ性3| 欧美成在线观看| 在线观看日韩欧美| 亚洲欧美国产精品| 在线精品91av| 青青草国产精品一区二区| 日韩中文在线中文网在线观看| 亚洲免费高清视频| yw.139尤物在线精品视频| 日韩美女激情视频| 国产精品久久久久国产a级| 国产精品一区二区3区| 精品女同一区二区三区在线播放| 欧美性少妇18aaaa视频| 久久人人97超碰精品888| 色狠狠av一区二区三区香蕉蜜桃| 精品免费在线观看| 中文字幕亚洲字幕| 日韩在线观看免费网站| 国产精品久久国产精品99gif| 26uuu国产精品视频| 91亚洲国产成人久久精品网站| 亚洲综合在线中文字幕| 亚洲电影免费观看高清完整版在线观看| 91在线|亚洲| 欧美性感美女h网站在线观看免费| 国产午夜精品美女视频明星a级| 久久免费成人精品视频| 国产精品va在线播放| 欧美高跟鞋交xxxxxhd| 日韩精品极品视频| 91美女片黄在线观看游戏| 国产精品视频一区二区高潮| 国产精品色视频| 亚洲电影av在线| 伊人男人综合视频网| 亚洲精品福利在线| 91在线观看免费网站| 精品久久国产精品| 欧美日本高清视频| 蜜臀久久99精品久久久久久宅男| 欧美另类在线播放| 久久久久99精品久久久久| www.欧美视频| 成人激情电影一区二区| 亚洲精品一区二区三区婷婷月| 欧美国产欧美亚洲国产日韩mv天天看完整| 91色精品视频在线| 伊人久久男人天堂| 久久久精品国产亚洲| 亚洲一区二区在线| 中文字幕日韩av综合精品| 日韩成人中文字幕| 色悠悠国产精品| 欧美激情视频在线| 中文字幕一区日韩电影| 96pao国产成视频永久免费| 欧美黄色片免费观看| 日韩电影视频免费| 国产视频观看一区| 最近免费中文字幕视频2019| 亚洲国产中文字幕久久网| 成人激情电影一区二区| 成人在线一区二区| 日韩精品免费在线播放| 国产美女久久精品香蕉69| 日韩一级裸体免费视频| 亚洲精品国产欧美| 日韩中文在线观看| 欧美裸体xxxx极品少妇| 亚洲国产精品99久久| 亚洲成av人片在线观看香蕉| 亚洲wwwav| 亚洲无线码在线一区观看| 国产精品揄拍500视频| 国产欧美精品xxxx另类| 国内精品一区二区三区| 久久视频在线播放| 国产亚洲欧美aaaa| 2019最新中文字幕| 国产一区二区三区在线播放免费观看| 国产日韩在线亚洲字幕中文| 久久久久国产一区二区三区| 精品亚洲男同gayvideo网站| 91精品久久久久久久久青青| 欧美激情按摩在线| 国产91精品久久久久久久| 亚洲国产欧美一区二区三区同亚洲| 久久综合九色九九| 亚洲电影免费在线观看| 亚洲精品欧美一区二区三区| 欧美性理论片在线观看片免费| 欧美成人免费小视频| 国产视频久久网| 97视频在线观看免费高清完整版在线观看| 亚洲欧美日韩精品久久亚洲区| 中文字幕一区日韩电影| 亚洲精品成人久久| 国产男人精品视频| 亚洲国产精彩中文乱码av| 久久久精品免费|