博客主页:https://blog.csdn.net/wkd_007
博客内容:嵌入式开发、Linux、C语言、C++、数据结构、音视频
本文内容:介绍C语言预处理的 #、##、__VA_ARGS__、##args
金句分享:
本文未经允许,不得转发!!!
#、##、##__VA_ARGS__、##args
这几个符号在C语言自定义的宏表达式
中,常常会看到,本文介绍这个符号的作用,以及列举几个简单例子,直观了解这几个符号的使用。
操作符 | 作用 |
---|---|
# | 将宏参数转换为字符串常量 |
## | 把多个语言符号组合成单个语言符号 |
__VA_ARGS__ | 表示可变参数列表 |
args | 表示可变参数列表 |
C语言中,#操作符
的作用是,将宏参数转换为字符串常量。
注意:#操作符
只会将 宏参数
转成字符串,在宏定义中,把#
接在其他符号前并不会将该符号变成字符串,只有接在 宏参数
前,变成字符串。
用法参考下面代码:
// preDel#.c
// gcc preDel#.c -E -o preDel#.i //预编译
// gcc preDel#.c // 编译
#include
#define MY_STR(x) #x
#define SQR(x) printf("The square of "#x" is %d.\n", ((x)*(x)));
#define CALL(fun) (printf("CALL %s\n", #fun), fun())
void function()
{
}
int main(void)
{
printf("%s\n", MY_STR(Hello world!));
SQR(8);
CALL(function); // 先打印函数名,再调用函数
return 0;
}
保存上面代码,执行gcc preDel#.c -E -o preDel#.i
,然后查看preDel#.i
的最后几行,可以看到#操作符
是怎么替换的,替换后代码如下:
# 5 "preDel#.c" 2
void function()
{
}
int main(void)
{
printf("%s\n", "Hello world!");
printf("The square of ""8"" is %d.\n", ((8)*(8)));;
(printf("CALL %s\n", "function"), function());
return 0;
}
从预处理的结果来看,宏函数里的字样#宏参数
都会被加上双引号替换成 "#宏参数"
的字符串。当我们需要在宏表达式里使用到宏参数的字符串时,就可以使用这个#操作符。
##操作符
的作用是,把多个语言符号组合成单个语言符号。
##
在宏定义中,连接多个符号;##
在宏定义中,连接一个固定符号到宏参数;##
在宏定义中,连接多个宏参数;##
在宏定义中,与__VA_ARGS__、args
宏一起使用。注意:##
连接后仍然是语言符号,不字加了双引号的字符串。
用法参考下面代码:
#include
#define CONNECT_TWO_SYBBOL abc##def // 连接两个符号为一个 adbdef
#define CONNECT_THREE_SYBBOL abc##def##ghi // 连接三个符号为一个 adbdefghi
#define CONNECT_SYMBOL_PARAM(x) char g_c##x // 连接符号和宏参数
#define CONNECT_PARAMS(x,y,z) g_##x##y##z // 连接多个宏参数
int main(void)
{
int CONNECT_TWO_SYBBOL;
int CONNECT_THREE_SYBBOL;
CONNECT_SYMBOL_PARAM(x);
int CONNECT_PARAMS(a,b,c);
return 0;
}
保存上面代码,执行gcc preDel##.c -E -o preDel##.i
,然后查看preDel##.i
的最后几行,可以看到##操作符
是怎么替换的,替换后代码如下:
# 2 "preDel##.c" 2
int main(void)
{
int abcdef;
int abcdefghi;
char g_cx;
int g_abc;
return 0;
}
从预处理的结果来看,##
操作符将多个符号连接成一个符号。
__VA_ARGS__
宏C 语言中 __VA_ARGS__
是一个可变参数的宏,是新的 C99 规范中新增的,需要配合 #define
使用。
__VA_ARGS__
的作用是,将左边宏表达式中可变参数 (…)
的内容原样抄写在右边 __VA_ARGS__
所在的位置。
注意:如果宏表达式的参数可能为空的话,需要在__VA_ARGS__
前面加##
,把多余的逗号 ,
去掉,否则会编译出错。
用法参考下面代码,LOG("no param\n");
这句会出错,编译时要注释掉:
// preDel_VA_ARGS.c
// gcc preDel_VA_ARGS.c -E -o preDel_VA_ARGS.i //预编译
// gcc preDel_VA_ARGS.c // 编译
#include
#define __TXT_(name, ...) char* g_txt_##name[]={__VA_ARGS__}
#define LOG(fmt,...) printf(fmt,__VA_ARGS__)
#define DEBUG_PRINT(fmt, ...) \
printf("[%s:%d] " fmt , __FILE__, __LINE__, ##__VA_ARGS__)
int main(void)
{
__TXT_(str, "this is str1", "this is str2");
LOG("str1=[%s]\n",g_txt_str[0]);
LOG("no param\n"); // 这里没有参数,会编译出错
DEBUG_PRINT("str2=[%s]\n",g_txt_str[1]);
DEBUG_PRINT("no param\n"); // 这里没有参数,不出错
return 0;
}
保存上面代码,执行gcc preDel_VA_ARGS.c -E -o preDel_VA_ARGS.i
,然后查看preDel_VA_ARGS.i
的最后几行,可以看到__VA_ARGS__
是怎么替换的,替换后代码如下:
# 2 "preDel_VA_ARGS.c" 2
int main(void)
{
char* g_txt_str[]={"this is str1", "this is str2"};
printf("str1=[%s]\n",g_txt_str[0]);
printf("no param\n",); // __VA_ARGS__前没加##,会多出逗号,导致编译出错
printf("[%s:%d] " "str2=[%s]\n" , "preDel_VA_ARGS.c", 11,g_txt_str[1]);
printf("[%s:%d] " "no param\n" , "preDel_VA_ARGS.c", 12);// __VA_ARGS__前加了##,不会多出逗号
return 0;
}
args
也是一个宏。它的作用与__VA_ARGS__
几乎一致,将左边宏表达式中可变参数 (args…)
的内容原样抄写在右边 args
所在的位置。
用法参考下面代码,把__VA_ARGS__
例子的代码,改成使用args
。LOG("no param\n");
这句会出错,编译时要注释掉:
// preDel_args.c
// gcc preDel_args.c -E -o preDel_args.i //预编译
// gcc preDel_args.c // 编译
#include
#define __TXT_(name, args...) char* g_txt_##name[]={args}
#define LOG(fmt, args...) printf(fmt,args)
#define DEBUG_PRINT(fmt, args...) \
printf("[%s:%d] " fmt , __FILE__, __LINE__, ##args)
int main(void)
{
__TXT_(str, "this is str1", "this is str2");
LOG("str1=[%s]\n",g_txt_str[0]);
LOG("no param\n"); // 这里没有参数,会编译出错
DEBUG_PRINT("str2=[%s]\n",g_txt_str[1]);
DEBUG_PRINT("no param\n"); // 这里没有参数,不出错
return 0;
}
保存上面代码,执行gcc preDel_args.c -E -o preDel_args.i
,然后查看preDel_args.i
的最后几行,可以看到args
是怎么替换的,替换后代码如下:
# 2 "preDel_args.c" 2
int main(void)
{
char* g_txt_str[]={"this is str1", "this is str2"};
printf("str1=[%s]\n",g_txt_str[0]);
printf("no param\n",);
printf("[%s:%d] " "str2=[%s]\n" , "preDel_args.c", 11,g_txt_str[1]);
printf("[%s:%d] " "no param\n" , "preDel_args.c", 12);
return 0;
}
从预处理后的结果来看,args
的处理结果和__VA_ARGS__
的处理结果是一样的。
本文详细介绍了 #操作符、##操作符、__VA_ARGS__
宏、args宏 的作用、用法、例子。
如果文章有帮助的话,点赞、收藏⭐,支持一波,谢谢