打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
C语言宏嵌套
C语言宏嵌套
【引用】C语言宏的嵌套问题  http://zhangzhibiao02005.blog.163.com/blog/static/37367820201182585935895/ (修改原文第二个程序中一处错误,return 1;改为return 0;CodeBlock下运行验证,并附上不包含stdio头文件的预处理后文件)
在C语言的宏中是容许嵌套的,其嵌套后,一般的展开规律像函数的参数一样,先展开参数,再分析函数,所以展开顺序是由内而外,但是当宏中有#则不再展开参数了,如果宏中有##,则先展开函数,再展开里面的参数。
如下面的例子:
#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;
}
它的输出结果为:
"ADDPARAM( 1 )"
PARAM( ADDPARAM( 1 ) )
对于宏TO_STRING,它的定义中没有#,所以先展开里面的“PARAM( ADDPARAM( 1 ) )”,由于PARAM中有#,所以里面展开的结果为ADDPARAM( 1 ),然后外面再展开,其结果为"ADDPARAM( 1 )"
而对于TO_STRING2,其定义中有#,所以直接展开,其结果为PARAM( ADDPARAM( 1 ) )
去掉include的预处理后文件为:
/*        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 */  }
注:\"为转义字符反斜杠表示的双引号。
而对于下面的例子:
#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;
}
其输出结果为:
a_PARAM( INT_1 )
因为首先分析TO_STRING的参数TO_STRING2(PARAM( ADDPARAM( 1 ) ) ),而对于TO_STRING2(x),由于其定义中有##,所以先展开该函数,其结果为a_PARAM(ADDPARAM( 1 )),而ADDPARAM( 1 )展开,结果为INT_1,所以其总结果为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 */  }
【引用结束】
【总结】
先展开宏,再展开宏参数,这种说法不太妥当,我总结的宏处理过程如下:
遇到宏名后(1)
  • 检查对应的宏体中是否含有#和##运算符
    • 无——处理宏参数(实参)(2)
      •  遇到宏名,回到(1)
      • 没有遇到,在宏体中用实参字符串替换形式参数,再检查是否遇到宏名(4)
        •  ...
    • 有——不检查宏参数,在宏体中用实参字符串替换形式参数,再检查是否含有宏名(3)
      • 遇到宏名,回到(1)
      •  没有遇到,结束(5)
详细地解释一下整个过程并做验证
【经典题过程】
#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)
    检查对应的宏体中是否含有#和##运算符
        无——处理宏参数(实参)(2)
            遇到宏名,回到(1)
            没有遇到,在宏体中用实参字符串替换形式参数,再检查是否遇到宏名(4)
                ...
        有——不检查宏参数,在宏体中用实参字符串替换形式参数,再检查是否含有宏名(3)
            遇到宏名,回到(1)
            没有遇到,结束(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 )"




本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
C语言宏嵌套的展开规则
详解C语言中的#define宏定义命令用法
代码自动生成-宏带来的奇技淫巧 - 紫月城游戏软件 - C 博客
C语言之#define用法(宏定义命令)
简述C语言宏定义的使用
编译预处理指令【精】
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服