日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

C語言宏嵌套

 renhl252 2015-03-21
C語言宏嵌套
【引用】C語言宏的嵌套問題  http://zhangzhibiao02005.blog.163.com/blog/static/37367820201182585935895/ (修改原文第二個程序中一處錯誤,return 1;改為return 0;CodeBlock下運行驗證,并附上不包含stdio頭文件的預(yù)處理后文件)
在C語言的宏中是容許嵌套的,其嵌套后,一般的展開規(guī)律像函數(shù)的參數(shù)一樣,先展開參數(shù),再分析函數(shù),所以展開順序是由內(nèi)而外,但是當(dāng)宏中有#則不再展開參數(shù)了,如果宏中有##,則先展開函數(shù),再展開里面的參數(shù)。
如下面的例子:
#include <stdio.h>
#define TO_STRING2( x ) #x
#define TO_STRING( x ) TO_STRING1( x )
#define TO_STRING1( x ) #x
#define PARAM( x ) #x
#define ADDPARAM( x ) INT_##x
int main()
{
    const char * str = TO_STRING(PARAM( ADDPARAM( 1 ) ) );
    printf("%s\n",str);
    str = TO_STRING2(PARAM( ADDPARAM( 1 ) ) );
    printf("%s\n",str);
    return 0;
}
它的輸出結(jié)果為:
"ADDPARAM( 1 )"
PARAM( ADDPARAM( 1 ) )
對于宏TO_STRING,它的定義中沒有#,所以先展開里面的“PARAM( ADDPARAM( 1 ) )”,由于PARAM中有#,所以里面展開的結(jié)果為ADDPARAM( 1 ),然后外面再展開,其結(jié)果為"ADDPARAM( 1 )"
而對于TO_STRING2,其定義中有#,所以直接展開,其結(jié)果為PARAM( ADDPARAM( 1 ) )
去掉include的預(yù)處理后文件為:
/*        6 */  int main ( )
/*        7 */  {
/*        8 */  const char * str = "\"ADDPARAM( 1 )\"" ;
/*        9 */  printf ( "%s\n" , str ) ;
/*       10 */  str = "PARAM( ADDPARAM( 1 ) )" ;
/*       11 */  printf ( "%s\n" , str ) ;
/*       12 */  return 0 ;
/*       13 */  }
注:\"為轉(zhuǎn)義字符反斜杠表示的雙引號。
而對于下面的例子:
#include <stdio.h>
#define TO_STRING2( x ) a_##x
#define TO_STRING( x ) TO_STRING1( x )
#define TO_STRING1( x ) #x
#define PARAM( x ) #x
#define ADDPARAM( x ) INT_##x
int main()
{
    const char *str = TO_STRING(TO_STRING2(PARAM( ADDPARAM( 1 ) ) ));
    printf("%s\n",str);
    return 0;
}
其輸出結(jié)果為:
a_PARAM( INT_1 )
因為首先分析TO_STRING的參數(shù)TO_STRING2(PARAM( ADDPARAM( 1 ) ) ),而對于TO_STRING2(x),由于其定義中有##,所以先展開該函數(shù),其結(jié)果為a_PARAM(ADDPARAM( 1 )),而ADDPARAM( 1 )展開,結(jié)果為INT_1,所以其總結(jié)果為a_PARAM( INT_1 )
/*        6 */  int main ( )
/*        7 */  {
/*        8 */  const char * str = "a_PARAM( INT_1)" ;
/*        9 */  printf ( "%s\n" , str ) ;
/*       10 */  return 0 ;
/*       11 */  }
【引用結(jié)束】
【總結(jié)】
先展開宏,再展開宏參數(shù),這種說法不太妥當(dāng),我總結(jié)的宏處理過程如下:
遇到宏名后(1)
  • 檢查對應(yīng)的宏體中是否含有#和##運算符
    • 無——處理宏參數(shù)(實參)(2)
      •  遇到宏名,回到(1)
      • 沒有遇到,在宏體中用實參字符串替換形式參數(shù),再檢查是否遇到宏名(4)
        •  ...
    • 有——不檢查宏參數(shù),在宏體中用實參字符串替換形式參數(shù),再檢查是否含有宏名(3)
      • 遇到宏名,回到(1)
      •  沒有遇到,結(jié)束(5)
詳細地解釋一下整個過程并做驗證
【經(jīng)典題過程】
#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)
h(f(1,2))    (2)        (1)(3)(5)
h(12)        (4)
g(12)                (1)(3)(5)
"12"
g(f(1,2))    (3)
"f(1,2)"     // 受字符串符號屏蔽
【對于那個討論帖的問題】
#define cat(a,b) a ## b
#define f(a) fff a
#define ab AB
cat(cat(1,2),3)
cat(1,2)3
cat(a,b)
ab
AB
f(cat(cat(1,2),3))
fff cat(cat(1,2),3)
fff cat(1,2)3

【例子1過程】
遇到宏名后(1)
    檢查對應(yīng)的宏體中是否含有#和##運算符
        無——處理宏參數(shù)(實參)(2)
            遇到宏名,回到(1)
            沒有遇到,在宏體中用實參字符串替換形式參數(shù),再檢查是否遇到宏名(4)
                ...
        有——不檢查宏參數(shù),在宏體中用實參字符串替換形式參數(shù),再檢查是否含有宏名(3)
            遇到宏名,回到(1)
            沒有遇到,結(jié)束(5)
#define TO_STRING2( x ) #x
#define TO_STRING( x ) TO_STRING1( x )
#define TO_STRING1( x ) #x
#define PARAM( x ) #x
#define ADDPARAM( x ) INT_##x
TO_STRING(PARAM( ADDPARAM( 1 ) ) )
TO_STRING("ADDPARAM( 1 )" )
TO_STRING1("ADDPARAM( 1 )" )
"\"ADDPARAM( 1 )\""
TO_STRING2(PARAM( ADDPARAM( 1 ) ) )
"PARAM( ADDPARAM( 1 ) )"
【例子2過程】
#define TO_STRING2( x ) a_##x
#define TO_STRING( x ) TO_STRING1( x )
#define TO_STRING1( x ) #x
#define PARAM( x ) #x
#define ADDPARAM( x ) INT_##x
TO_STRING(TO_STRING2(PARAM( ADDPARAM( 1 ) ) ))
TO_STRING(a_PARAM( ADDPARAM( 1 ) ))
TO_STRING(a_PARAM( INT_1 ))
TO_STRING1(a_PARAM( INT_1 ))
"a_PARAM( INT_1 )"




    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多