C语言中宏定义"#"和"##"符号的用法
2016-04-25 16:28
1026 查看
C语言中宏有两个非常有用的宏符号“#”“##”这两个符号的用法总结如下。
#把宏参数变为一个字符串而##把两个宏参数贴合在一起。
一、一般用法
#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;
}
二、宏参数是另一个宏
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";
带有可变参数的宏( Macros with a Variable Number of Arguments )
在 1999 年版本的 ISO C 标准中,宏可以象函数一样,定义时可以带有可变参数。宏的语法和函数的语法类似。下面有个例子:
#define debug(format, ...) fprintf (stderr, format, __VA_ARGS__)
这里,‘ … ’指可变参数。这类宏在被调用时,它(这里指‘ … ’)被表示成零个或多个符号,包括里面的逗号,一直到到右括弧结束为止。当被调用时,在宏体( macro body )中,那些符号序列集合将代替里面的 __VA_ARGS__ 标识符。更多的信息可以参考 CPP 手册。
GCC 始终支持复杂的宏,它使用一种不同的语法从而可以使你可以给可变参数一个名字,如同其它参数一样。例如下面的例子:
#define debug(format, args...) fprintf (stderr, format, args)
这和上面举的那个 ISO C 定义的宏例子是完全一样的,但是这么写可读性更强并且更容易进行描述。
GNU CPP 还有两种更复杂的宏扩展,支持上面两种格式的定义格式。
在标准 C 里,你不能省略可变参数,但是你却可以给它传递一个空的参数。例如,下面的宏调用在 ISO C 里是非法的,因为字符串后面没有逗号:
debug ("A message")
GNU CPP 在这种情况下可以让你完全的忽略可变参数。在上面的例子中,编译器仍然会有问题( complain ),因为宏展开后,里面的字符串后面会有个多余的逗号。
为了解决这个问题, CPP 使用一个特殊的‘ ## ’操作。书写格式为:
#define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
这里,如果可变参数被忽略或为空,‘ ## ’操作将使预处理器( preprocessor )去除掉它前面的那个逗号。如果你在宏调用时,确实提供了一些可变参数, GNU CPP 也会工作正常,它会把这些可变参数放到逗号的后面。象其它的 pasted macro 参数一样,这些参数不是宏的扩展。
#把宏参数变为一个字符串而##把两个宏参数贴合在一起。
一、一般用法
#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;
}
二、宏参数是另一个宏
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";
可变参数的宏里的‘##’操作说明
带有可变参数的宏( Macros with a Variable Number of Arguments )在 1999 年版本的 ISO C 标准中,宏可以象函数一样,定义时可以带有可变参数。宏的语法和函数的语法类似。下面有个例子:
#define debug(format, ...) fprintf (stderr, format, __VA_ARGS__)
这里,‘ … ’指可变参数。这类宏在被调用时,它(这里指‘ … ’)被表示成零个或多个符号,包括里面的逗号,一直到到右括弧结束为止。当被调用时,在宏体( macro body )中,那些符号序列集合将代替里面的 __VA_ARGS__ 标识符。更多的信息可以参考 CPP 手册。
GCC 始终支持复杂的宏,它使用一种不同的语法从而可以使你可以给可变参数一个名字,如同其它参数一样。例如下面的例子:
#define debug(format, args...) fprintf (stderr, format, args)
这和上面举的那个 ISO C 定义的宏例子是完全一样的,但是这么写可读性更强并且更容易进行描述。
GNU CPP 还有两种更复杂的宏扩展,支持上面两种格式的定义格式。
在标准 C 里,你不能省略可变参数,但是你却可以给它传递一个空的参数。例如,下面的宏调用在 ISO C 里是非法的,因为字符串后面没有逗号:
debug ("A message")
GNU CPP 在这种情况下可以让你完全的忽略可变参数。在上面的例子中,编译器仍然会有问题( complain ),因为宏展开后,里面的字符串后面会有个多余的逗号。
为了解决这个问题, CPP 使用一个特殊的‘ ## ’操作。书写格式为:
#define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
这里,如果可变参数被忽略或为空,‘ ## ’操作将使预处理器( preprocessor )去除掉它前面的那个逗号。如果你在宏调用时,确实提供了一些可变参数, GNU CPP 也会工作正常,它会把这些可变参数放到逗号的后面。象其它的 pasted macro 参数一样,这些参数不是宏的扩展。
相关文章推荐
- 验证码切分程序
- Reverse Words in a String
- C语言中的变参数函数,宏
- malloc calloc realloc的对比
- C语言压缩文件和用MD5算法校验文件完整性的实例教程
- 将VIM改造成c++IDE
- C++栈的实现(针对某种数据类型)
- C语言中交换int型变量的值及转换为字符数组的方法
- C++程序员发展方向
- C++ 语言宏定义函数的使用(定义单行和多行)
- 从尾到头打印链表中每个节点的值(采用栈实现)
- 一波C语言字符数组实用技巧集锦
- c/c++ 关于字符串转换的总结
- 《Windows API》01 简介
- C++ 中extern"C"
- C/C++复习:统计票数
- 逆波兰表达式 转换和计算 C++实现
- C语言程序中递归算法的使用实例教程
- C/C++复习:计算该日期是本年中的第几天(优化版2)
- C++第四次作业-1000以内偶数和和乘法口诀表