#define FLOG_OUTPUT(arg...) printf(##arg) 这个宏定义如何理解 ?

aihua1981 2009-02-23 09:38:51
ALL,
我在阅读公司的代码中发现有这么一个宏定义
#define FLOG_OUTPUT(arg...) printf(##arg)
有两个地方不同,请问下大伙儿:
(arg...) 中arg后面3点表示什么意思,(##arg) 中arg之前的2个## 又表示什么意思?
在使用时 FLOG_OUTPUT("flog_hcb_format(): starting...\n"); 打印出什么结果

请路过 知晓的 慷慨解答了
谢谢
...全文
1974 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
aihua1981 2009-02-23
  • 打赏
  • 举报
回复
多谢楼上各位兄弟,特别是1楼的朋友 给出了这么详细的说明。
看后基本明白了。
再次感谢各位
ltc_mouse 2009-02-23
  • 打赏
  • 举报
回复
#define FLOG_OUTPUT(arg...) printf(##arg)
-----------
任意参数的宏,gcc扩展, 加上##表示arg之后可以没有其他参数.下面两条语句都能被正确扩展.
FLOG_OUTPUT("It runs here\n");
FLOG_OUTPUT("Receive msg=%ld\n", msgId);
lzonline01 2009-02-23
  • 打赏
  • 举报
回复
1楼说的正确,
happytang 2009-02-23
  • 打赏
  • 举报
回复
在使用时 FLOG_OUTPUT("flog_hcb_format(): starting...\n"); 打印出什么结果


flog_hcb_format(): starting...
happytang 2009-02-23
  • 打赏
  • 举报
回复
有两个地方不同,请问下大伙儿:
(arg...) 中arg后面3点表示什么意思,(##arg) 中arg之前的2个## 又表示什么意思?

/////////////////////
1表示参数不确定,因为字符串打印参数可以多个,比如还可以打印%s参数,或者打印代码的行号;看你们怎么设计了
2表示多个参数连在一起输出
pengzhixi 2009-02-23
  • 打赏
  • 举报
回复
3点应该是参数个数不确定的时候就用这个省略号
waizqfor 2009-02-23
  • 打赏
  • 举报
回复 2
[Quote=引用楼主 aihua1981 的帖子:]
ALL,
我在阅读公司的代码中发现有这么一个宏定义
#define FLOG_OUTPUT(arg...) printf(##arg)
有两个地方不同,请问下大伙儿:
(arg...) 中arg后面3点表示什么意思,(##arg) 中arg之前的2个## 又表示什么意思?
在使用时 FLOG_OUTPUT("flog_hcb_format(): starting...\n"); 打印出什么结果

请路过 知晓的 慷慨解答了
谢谢
[/Quote]
宏中"#"和"##"的用法
一、一般用法
我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起.
用法:
#include<cstdio>
#include<climits>
using namespace std;

#define STR(s) #s
#define CONS(a,b) int(a##e##b)

int main()
{
printf(STR(vck)); // 输出字符串"vck"
printf("%d
", CONS(2,3)); // 2e3 输出:2000
return 0;
}

二、当宏参数是另一个宏的时候
需要注意的是凡宏定义里有用'#'或'##'的地方宏参数是不会再展开.

1, 非'#'和'##'的情况
#define TOW (2)
#define MUL(a,b) (a*b)

printf("%d*%d=%d
", TOW, TOW, MUL(TOW,TOW));
这行的宏会被展开为:
printf("%d*%d=%d
", (2), (2), ((2)*(2)));
MUL里的参数TOW会被展开为(2).

2, 当有'#'或'##'的时候
#define A (2)
#define STR(s) #s
#define CONS(a,b) int(a##e##b)

printf("int max: %s
", STR(INT_MAX)); // INT_MAX #include<climits>
这行会被展开为:
printf("int max: %s
", "INT_MAX");

printf("%s
", CONS(A, A)); // compile error
这一行则是:
printf("%s
", int(AeA));

INT_MAX和A都不会再被展开, 然而解决这个问题的方法很简单. 加多一层中间转换宏.
加这层宏的用意是把所有宏的参数在这层里全部展开, 那么在转换宏里的那一个宏(_STR)就能得到正确的宏参数.

#define A (2)
#define _STR(s) #s
#define STR(s) _STR(s) // 转换宏
#define _CONS(a,b) int(a##e##b)
#define CONS(a,b) _CONS(a,b) // 转换宏

printf("int max: %s
", STR(INT_MAX)); // INT_MAX,int型的最大值,为一个变量 #include<climits>
输出为: int max: 0x7fffffff
STR(INT_MAX) --> _STR(0x7fffffff) 然后再转换成字符串;

printf("%d
", CONS(A, A));
输出为:200
CONS(A, A) --> _CONS((2), (2)) --> int((2)e(2))

三、'#'和'##'的一些应用特例
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、得到一个数值类型所对应的字符串缓冲大小
#define _TYPE_BUF_SIZE(type) sizeof #type
#define TYPE_BUF_SIZE(type) _TYPE_BUF_SIZE(type)
char buf[TYPE_BUF_SIZE(INT_MAX)];
--> char buf[_TYPE_BUF_SIZE(0x7fffffff)];
--> char buf[sizeof "0x7fffffff"];
这里相当于:
char buf[11];
源码直接下载地址: https://pan.quark.cn/s/a4b39357ea24 平台简介 License Spring Boot JDK-17 本项目基于ruoyi-vue-fast实现 项目代码、文档 均开源免费可商用 遵循开源协议在项目中保留开源协议文件即可 活到老写到老 为兴趣而开源 为学习而开源 为让大家真正可以学到技术而开源 若依wms是一套基于若依的wms仓库管理系统,支持lodop和网页打印入库单、出库单。 毫无保留给个人及企业免费使用。 前端采用Vue、Element UI。 后端采用Spring Boot、Spring Security、Redis & Jwt。 权限认证使用Jwt,支持多终端认证系统。 支持加载动态权限菜单,多方式轻松权限控制。 高效率开发,使用代码生成器可以一键生成前后端代码。 前端项目地址 gitee https://gitee.com/zccbbg/ruo-yi-wms-vue https://.com/zccbbg/RuoYi-WMS-VUE 若依实战技术专栏 关注文末公众号回复:星球 在线体验 https://wms.ichengle.top/ 不同分支介绍 jdk17+vue3,支持多仓库,没有库区概念,操作简单,覆盖大部分库存应用场景。 jdk17+vue3,支持多仓库、多库区,记录生产日期、过期日期、sn,可适配一物一码,操作相对复杂。 jdk8+vue2 同步lite分支 若依wms功能 首页:库存预警与到期提醒、基础数据报表展示 仓库/库区:管理维护仓库基础数据 物料:管理维护物料基础数据 客户/供应商:管理维护联系人基础数据 入库:创建入库单后包括如下几个状态:暂存、作废、完成入库,入库类型包括:采购...

70,039

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧