#把宏参数变为一个字符串,而##把两个宏参数贴合在一起。
一、一般用法:
#include <stdio.h>
#define STR(s) #s
#define CONSS(a,b) (int)a##e##b
int main()
{
printf(STR(vck)); // 输出字符串"vck"
printf("/n");
printf("%d/n",CONSS(2,3)); // 2e3 输出:2000
return 0;
}
#注意:
a。忽略传入参数名前面和后面的空格。
如:str=example1( abc ); 将会被扩展成 str="abc";
b.当传入参数名间存在空格时,编译器将会自动连接各个子字符串,用每个子字符串中只以一个空格连接,忽略其中多余一个的空格。
##注意
1.当用##连接形参时,##前后的空格可有可无。
如:#define exampleNum(n) num ## n 相当于 #define exampleNum(n) num##n
2.连接后的实际参数名,必须为实际存在的参数名或是编译器已知的宏定义
二、宏参数是另一个宏
1、非'#'和'##'的情况:
#include <stdio.h>
#define TOW (2)
#define MUL(a,b) (a*b)
int main()
{
printf("%d*%d=%d/n", TOW, TOW, MUL(TOW,TOW));
return 0;
}
展开的结果是:
printf("%d*%d=%d/n", (2), (2), ((2)*(2)));
所以:没有使用#符号时,会递归的全部展开。
2、 当有'#'或'##'的时候
需要注意的是凡宏定义里有用'#'或'##'的地方宏参数是不会再展开。如下:
#include <stdio.h>
#define INT_MAX 0x7fffffff
#define STR(s) #s
int main()
{
printf("int max: %s/n", STR(INT_MAX)); //输出:int max: INT_MAX
printf("int max: %d/n", INT_MAX); //输出:int max: 2147483647
return 0;
}
如果定义:
#include <stdio.h>
#define A (2)
#define CONSS(a,b) (int)a##e##b
int main()
{
printf("%d/n", CONSS(A,A));
return 0;
}
则编译时会报错,因为无法将A展开,所以(int)(2)e(2)会出错。
解决办法:加多一层中间转换宏。加这层宏的用意是把所有宏的参数在这层里全部展开, 那么在转换宏里的那一个宏就能得到正确的宏参数。
#include <stdio.h>
#define A 2
#define _STR(s) #s
#define STR(s) _STR(s) // 转换宏
#define _CONSS(a,b) (int)a##e##b
#define CONSS(a,b) _CONSS(a,b) // 转换宏
int main()
{
printf("%d/n", CONSS(A,A));
printf("%d/n", STR(A));
return 0;
}
三、'#'和'##'的一些应用特例
1、合并匿名变量名
#define ___ANONYMOUS1(type, var, line) type var##line
#define __ANONYMOUS0(type, line) ___ANONYMOUS1(type, _anonymous, line)
#define ANONYMOUS(type) __ANONYMOUS0(type, __LINE__)
例:ANONYMOUS(static int); 即: static int _anonymous70; 70表示该行行号;
第一层:ANONYMOUS(static int); --> __ANONYMOUS0(static int, __LINE__);
第二层: --> ___ANONYMOUS1(static int, _anonymous, 70);
第三层: --> static int _anonymous70;
即每次只能解开当前层的宏,所以__LINE__在第二层才能被解开;
2、填充结构
#define FILL(a) {a, #a}
enum IDD{OPEN, CLOSE};
typedef struct MSG{
IDD id;
const char * msg;
}MSG;
MSG _msg[] = {FILL(OPEN), FILL(CLOSE)};
相当于:
MSG _msg[] = {{OPEN, "OPEN"},
{CLOSE, "CLOSE"}};
3、记录文件名
#define _GET_FILE_NAME(f) #f
#define GET_FILE_NAME(f) _GET_FILE_NAME(f)
static char FILE_NAME[] = GET_FILE_NAME(__FILE__);
4、得到一个数值类型所对应的字符串缓冲大小
#include <stdio.h>
#define INT_MAX 0x7fffffff
#define _TYPE_BUF_SIZE(type) sizeof #type
#define TYPE_BUF_SIZE(type) _TYPE_BUF_SIZE(type)
int main()
{
printf("%d/n", TYPE_BUF_SIZE(INT_MAX)); //11
return 0;
}
相当于:
TYPE_BUF_SIZE(INT_MAX)—>_TYPE_BUF_SIZE(0x7fffffff)—>sizeof "0x7fffffff";
3、@# (charizing)字符化操作符。
只能用于有传入参数的宏定义中,且必须置于宏定义体中的参数名前。作用是将传的单字符参数名转换成字符,以一对单引用括起来。
#define makechar(x) #@x
a = makechar(b);
展开后变成了:
a= 'b';