【C语言】关于宏定义中#和##符号的使用和宏定义展开问题

转自:http://www.linuxidc.com/Linux/2014-06/102925.htm

#是把宏参数变为一个字符串,##是把两个宏参数连接在一起。

有一道经典的C语言问题,关于宏定义中#和##符号的使用和宏定义展开问题
 
程序如下:

#include <stdio.h>
#define f(a,b) a##b
#define g(a)  #a
#define h(a) g(a)
 
int main()
{
        printf("%s\n", h(f(1,2)));
        printf("%s\n", g(f(1,2)));
        return 0;
}

答案:第一行:12  第二行:f(1,2)

说明:

1、关于符号#和##

两个符号都只能用于预处理宏扩展。不能在普通的源码中使用它们,只能在宏定义中使用。

简单的说,#是把宏参数变为一个字符串,##是把两个宏参数连接在一起。

关于这两个符号的具体意义和用法可以参见两篇文章:

#和##在宏替换中的作用 http://www.linuxidc.com/Linux/2014-06/102921.htm

C/C++ 宏中"#"和"##"的用法 http://www.linuxidc.com/Linux/2014-06/102924.htm

还有GCC帮助文档上的解释:

3.4 Stringification

3.5 Concatenation

2、关于宏展开

预处理过程的几个步骤:

1)字符集转换(如三联字符)

2)断行链接/

3)注释处理,/* comment */,被替换成空格

4)执行预处理命令,如#inlcude、#define、#pragma、#error等

5)转义字符替换

6)相邻字符串拼接

7)将预处理记号替换为词法记号

第4)步即如何展开宏函数的规则:在展开当前宏函数时,如果形参有#或##则不进行宏参数的展开,否则先展开宏参数,再展开当前宏。

宏替换顺序英文描述如下:

A parameter in the replacement list, unless preceded by a # or ## preprocessing token or followed by a ## preprocessing token, is replaced by the corresponding argument after all macros contained therein have been expanded.

3、总结

综合以上,对于这道题来说,第一行h(f(1,2)),由于h(a)非#或者##所以先展开其参数f(1,2),即12,所以变成h(12),然后再宏替换为g(12),再次替换为12。

第二行g(f(1,2)),宏g(a)带有#,所以里面的f(1,2)不展开,所以变成f(1,2)

类似的这种问题在《你必须知道的495个C语言问题》中出现过,在121页的“预处理功能”的问题11.19,有兴趣的朋友可以看一看。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值