C/C++:宏定义中的#与##

97 篇文章 7 订阅

C/C++:宏定义中的#与##


测试环境:CentOS


[mytmp@localhost ~]$ uname -a
Linux localhost.localdomain 2.6.18-371.el5 #1 SMP Thu Sep 5 21:21:44 EDT 2013 x86_64 x86_64 x86_64 GNU/Linux
[mytmp@localhost ~]$ gcc --version
gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-54)

在宏定义中,使用#可以将参数变成一个字符串,使用##可以将参数粘合在一起。


#include <stdio.h>
#include <stdlib.h>

#define NUM(n) #n
#define MYPASTE(n, m) n##01##m 

int main()
{
    printf("%d\n", 10);
    printf("%s\n", NUM(11));
    printf("%d\n", MYPASTE(2, 7));
    return 0;
}

[mytmp@localhost ~]$ gcc -E main.c
……
int main()
{
 printf("%d\n", 10);
 printf("%s\n", "11");
 printf("%d\n", 2017);
 return 0;
}

输出如下:

[mytmp@localhost ~]$ ./main
10
11
2017

可以看到#起到了将一个数字转变为字符串的功能;

##可将多部分直接黏连在一起。


#以及##出现在宏定义中的展开问题:


#include <stdio.h>
#include <stdlib.h>

#define NUM 6
#define S_NUM(num) #num
#define PASTE_NUM(a, b) a##b

int main()
{
    printf("%s\n", S_NUM(NUM));
    printf("%d\n", PASTE_NUM(NUM, NUM));
    return 0;
}

[mytmp@localhost ~]$ gcc -E main.c


预编译输出如下:


……
int main()
{
 printf("%s\n", "NUM");
 printf("%d\n", NUMNUM);
 return 0;
}

这个例子什么意思呢?


现在有个宏是NUM,当它传入到另外一个宏:S_NUM中时,会不会展开。


显然是不会的,因为在S_NUM的定义中使用了#,即后半部分:#num。


到最后就是#NUM,NUM不会被替换为对应的数字(6),不会展开。


简单点来说:#MACRO时,MACRO是一个宏,MACRO不会展开。


##同理。


##可以看到最后直接是符号级别的黏连在一起了,并没有展开为66(NUM##NUM-》NUM)。


有没有展开的办法?--》多使用一层宏来展开:


#include <stdio.h>
#include <stdlib.h>

#define NUM 6
#define S_NUM(num) #num
#define S_NUM1(num) S_NUM(num)
#define PASTE_NUM(a, b) a##b
#define PASTE_NUM1(a, b) PASTE_NUM(a, b) 

int main()
{
    printf("%s\n", S_NUM1(NUM));
    printf("%d\n", PASTE_NUM1(NUM, NUM));
    return 0;
}

预编译之后为:


……
int main()
{
 printf("%s\n", "6");
 printf("%d\n", 66);
 return 0;
}

输出结果为:


[mytmp@localhost ~]$ gcc -o main main.c
[mytmp@localhost ~]$ ./main
6
66

很明显,多加了一层展开了宏。


有可能是这么一个流程:首先遇到了S_NUM1(NUM),看了下S_NUM1的宏定义,没有啥#开头的,那么就用NUM替换掉S_NUM1,这样就是S_NUM(6),接下来发现是#num,再将其转换为字符串。

核心的是:增加的那一层,没有#/##,使得宏参数展开,继而不会产生#/##出现展不开的问题。

另一个不再赘述。


现在我们看一个例子。


有这么一个宏:


#include <stdio.h>
#include <stdlib.h>

#define AT __FILE__":"__LINE__

int main()
{
    printf("%s\n", AT);
    return 0;
}

本意是输出__FILE__以及__LINE__,但是实际预编译后为:


int main()
{
 printf("%s\n", "main.c"":"8);
 return 0;
}

究其原因,是__LINE__并不是字符串,而是个数字。


呀,我可以使用#来将其转换下:


#define AT __FILE__":"#__LINE__

预编译是:


printf("%s\n", "main.c"":"#8);

换个宏定义试试:


#include <stdio.h>
#include <stdlib.h>

#define CONVERT(x) #x
#define AT __FILE__":"CONVERT(__LINE__)

int main()
{
    printf("%s\n", AT);
    return 0;
}

预编译后是:


int main()
{
 printf("%s\n", "main.c"":""__LINE__");
 return 0;
}

结果并不奇怪,仔细想想,宏展开了嘛?当然没有。我们之前说怎么展开来着?


增加一层“宏参数展开层”。


#include <stdio.h>
#include <stdlib.h>

#define CONVERT(x) #x
#define CONVERT1(x) CONVERT(x)
#define AT __FILE__":"CONVERT1(__LINE__)

int main()
{
    printf("%s\n", AT);
    return 0;
}

预编译之后如下:


int main()
{
 printf("%s\n", "main.c"":""10");
 return 0;
}

输出结果如下:


[mytmp@localhost ~]$ ./main
main.c:10

成功。


参考资料:


1.http://blog.csdn.net/tomtc123/article/details/8875468

2.http://www.cnblogs.com/lzjsky/archive/2010/11/24/1886690.html

3.http://www.blogjava.net/cxzforever/articles/356583.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值