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

来源:互联网 发布:python turtle 坐标 编辑:程序博客网 时间:2024/06/18 17:33

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


测试环境:CentOS


[mytmp@localhost ~]$ uname -aLinux 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 --versiongcc (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 ~]$ ./main10112017

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

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


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


#include <stdio.h>#include <stdlib.h>#define NUM 6#define S_NUM(num) #num#define PASTE_NUM(a, b) a##bint 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 ~]$ ./main666

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


有可能是这么一个流程:首先遇到了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 ~]$ ./mainmain.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 0
原创粉丝点击