以下一例。
#define DEBUG(fmt,args...) printf("STRING CAT"fmt,##args);
DEBUG("EX:");
DEBUG("EX:%d",1);
http://blog.chinaunix.net/uid-1771330-id-2863781.html
有时我们写程序可能会定义许多DEBUG模式下的调试打印信息宏来替代原有的打印函数,这时就会出现编写可变量参数宏的写法问题,下面就摘要性的写一下,运行及调试环境为rh linux 9.0+gcc 3.2.2
首先在gcc中,对可变量参数宏的支持要强的多,一般我们可以这么写:
#define MACRO_1(fmt, args...) printf(fmt, args)
#define MACRO_2(fmt, ...) printf(fmt, __VA_ARGS__)
这两种写法都可以,后面一种是使用了关键字__VA_ARGS__,它代表宏中出现的...,而前面的写法就是给可变量的参数定义了一个名字,就是说在第一种写法中,args就是代表可变量参数,给出例子:
#include <stdio.h>
#define MACRO_1(fmt, args...) printf(fmt, args)
#define MACRO_2(fmt, ...) printf(fmt, __VA_ARGS__)
#define MACRO_2(fmt, ...) printf(fmt, __VA_ARGS__)
int main()
{
MACRO_1("MACRO_1:%s\n", "Hello");
MACRO_2("MACRO_2:%s\n", "Hello");
return 0;
}
我们可以用gcc -E的参数来得到程序的宏展开源代码,主要部分如下:
{
MACRO_1("MACRO_1:%s\n", "Hello");
MACRO_2("MACRO_2:%s\n", "Hello");
return 0;
}
我们可以用gcc -E的参数来得到程序的宏展开源代码,主要部分如下:
int main()
{
printf("MACRO_1:%s\n", "Hello");
printf("MACRO_2:%s\n", "Hello");
return 0;
}
大家可以看到这里的对比.但有一个问题就是,如果我们只传递一个参数会怎么呢?也就是把源代码改写如下:
#include <stdio.h>
#define MACRO_1(fmt, args...) printf(fmt, args)
#define MACRO_2(fmt, ...) printf(fmt, __VA_ARGS__)
#define MACRO_2(fmt, ...) printf(fmt, __VA_ARGS__)
int main()
{
MACRO_1("MACRO_1\n");
MACRO_2("MACRO_2\n");
return 0;
}
{
MACRO_1("MACRO_1\n");
MACRO_2("MACRO_2\n");
return 0;
}
这样会不会有问题呢,我们看一下宏展开后的代码:
int main()
{
printf("MACRO_1\n" , );
printf("MACRO_2\n" , );
return 0;
}
{
printf("MACRO_1\n" , );
printf("MACRO_2\n" , );
return 0;
}
这里多出现了一个",",问题的解决方法是在args和__VA_ARGS__前面加一个##,##表示去除它前面的",",但当我们传递多于一个参数的时候这也能工作,就像第一段代码一样,现在看一下加了##之后的代码及相应宏展开后的代码:
#include <stdio.h>
#define MACRO_1(fmt, args...) printf(fmt, ##args)
#define MACRO_2(fmt, ...) printf(fmt, ##__VA_ARGS__)
#define MACRO_2(fmt, ...) printf(fmt, ##__VA_ARGS__)
int main()
{
MACRO_1("MACRO_1\n");
MACRO_2("MACRO_2\n");
return 0;
}
展开宏之后:
{
MACRO_1("MACRO_1\n");
MACRO_2("MACRO_2\n");
return 0;
}
展开宏之后:
int main()
{
printf("MACRO_1\n");
printf("MACRO_2\n");
return 0;
}
问题解决了~_~。
{
printf("MACRO_1\n");
printf("MACRO_2\n");
return 0;
}
问题解决了~_~。
其实,##在c语言里功能不只是这个,它还可以起到连接两个变量的作用,看下面的代码:
#include <stdio.h>
#define UNION(a,b) (a##b)
int main()
{
char* long_long_var_prt = "Hello,world!";
printf("Test:\nSTR:%s\tNUM:%d\n", UNION(long_, long_var_prt), UNION(10,8));
return 0;
}
这里开了一个小玩笑,就是把一个字符串的名字起得很长,然后再通过##把它们粘起来并输入,后面是把两个整数合并到一起,组成一个大的整数,展开宏之后的代码如下:
{
char* long_long_var_prt = "Hello,world!";
printf("Test:\nSTR:%s\tNUM:%d\n", UNION(long_, long_var_prt), UNION(10,8));
return 0;
}
这里开了一个小玩笑,就是把一个字符串的名字起得很长,然后再通过##把它们粘起来并输入,后面是把两个整数合并到一起,组成一个大的整数,展开宏之后的代码如下:
int main()
{
char* long_long_var_prt = "Hello,world!";
printf("Test:\nSTR:%s\tNUM:%d\n", ( long_long_var_prt), ( 108));
return 0;
}
输出如下:
{
char* long_long_var_prt = "Hello,world!";
printf("Test:\nSTR:%s\tNUM:%d\n", ( long_long_var_prt), ( 108));
return 0;
}
输出如下:
Test:
STR:Hello,world! NUM:108
OVER,快乐编程。
STR:Hello,world! NUM:108
OVER,快乐编程。