①一個較長的宏定義可以分成若干行,這需要在待續的行末尾加上一個反斜杠符”\”
#define TUP_ASSERT(__expression) do {\
if (!( __expression )) \
{ \
SYSLOG_LEGACY(EAaSysLogSeverityLevel_Error,"<TUP ASSERTION FAILED> (%s) file: %s line:%u", #__expression,__FILE__, __LINE__); \
AaErrorAssertion(#__expression,__FILE__, __LINE__); \
} \
} while(0)
②在替換文本中,參數名以#作為前綴則結果將被擴展為由實際參數替換該參數的帶引號的字符串
#define dprint(expr) printf(#expr “ =%g\n”, expr)
使用語句dprint(x/y),該宏將被擴展為
printf(“x/y” “= %g\n”, x/y);
③預處理運算符##為宏展開提供參數連接的作用
#define paste(front, back) front ##back
宏調用paste(name,1)的結果將建立記號name1
④宏展開順序大致可以歸結為:
第一步:首先用實參代替形參,將實參代入宏文本中
第二步:如果實參也是宏,則展開實參
第三步:最后繼續處理宏替換后的宏文本,如果仍包含宏,則繼續展開
注意:如果在第二步,實參代入宏文本后,實參之前或之后遇到#或##,實參不再展開
例1:
#define cat(a,b) a ## b
宏調用:cat(cat(1, 2), 3) 的展開順序為:
cat(cat(1, 2), 3) -->cat(1, 2) ## 3 -->cat(1, 2)3
cat(1,2)仍是宏,但后面是##,不再展開,結果為:cat(1, 2)3
例2:
#define cat(a,b) a ## b
#define xcat(x, y) cat(x, y)
宏調用 xcat(xcat(1, 2), 3) 的展開順序為:
xcat(xcat(1,2), 3) -->cat(xcat(1, 2), 3) -->cat(cat(1, 2), 3) -->cat(1 ## 2, 3) --> 1 ##2 ## 3 -->123
務必注意參數的處理順序,第二步在第三步前面執行,第一層宏展開后,實參是宏,則首先處理實參的宏展開,即使宏替換后本身也是宏。在例2中,雖然也生成的cat(cat(1, 2), 3),但是是首先執行里面的cat(1, 2), 所以結果不一樣。例2中以下順序是錯的:
xcat(xcat(1,2), 3) --> cat(xcat(1, 2), 3) --> xcat(1, 2) ## 3 -->xcat(1, 2)3
在Linux測試結果:
使用gcc –E 編譯可以只做預處理:源文件hepeng.c:
*****************************************************************************
#define cat(a,b) a ## b
#define xcat(x,y) cat(x,y)
int main()
{
cat(cat(1,2),3);
xcat(xcat(1,2),3);
xcat(cat(1,2),3);
return 0;
}
*****************************************************************************
[penhe@hzling23 program]$gcc -E hepeng.c |more
*****************************************************************************
# 1 "hepeng1.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "hepeng1.c"
int main()
{
cat(1,2)3;
123;
123;
return 0;
}
*****************************************************************************
boost 中包含了許多奇技淫巧的代碼,這里分析宏的自身迭代
以這樣的宏代碼調用
1 |
|
它的宏展開為
1 |
|
這在boost中被多用於簡化代碼量 比如 boos::function 中
下面來分析這類宏的具體實現
宏1:
1 |
|
首先看看 BOOST_PP_ENUM_PARAMS_M 的作用
宏2:
1 |
|
由宏2,可以看出,宏1展開為
1 |
|
BOOST_PP_AUTO_REC(BOOST_PP_REPEAT_P, 4) 其實就是 1,這個是一個定值,在目前,我們不必去深究 那么, BOOST_PP_CAT 就可以展開為
1 |
|
BOOST_PP_REPEAT_1 是一個非常簡單的迭代宏
1 2 3 4 5 6 7 |
|
所以
1 |
|
展開就等於
1 2 3 4 |
|
BOOST_PP_ENUM_PARAMS_M 自然也是一個宏
1 |
|
所以就有
1 2 |
|
BOOST_PP_COMMA_IF 是一個這樣的宏,如果參數非0,那么打印出逗號,否則就不打印逗號
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
可以看出,宏多用窮舉