首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

__VA_ARGS__宏扩展

宏扩展是C语言中的一种预处理技术,它允许在编译阶段将宏定义替换为指定的代码。宏扩展的主要目的是为了简化代码、增加可读性和可维护性。

宏扩展的基本语法如下:

代码语言:c
复制
#define 宏名(参数列表) 宏定义

其中,宏名是宏的名称,参数列表是可选的,宏定义是宏替换的代码。

在宏定义中,可以使用参数列表中的参数,也可以使用预定义的宏。例如:

代码语言:c
复制
#define MAX(a, b) ((a) > (b) ? (a) : (b))

这个宏定义可以用来比较两个数的大小,并返回较大的数。

在使用宏扩展时,需要注意以下几点:

  1. 宏定义中的参数不需要加上括号,但在使用宏时需要加上括号。
  2. 宏定义中的参数可以使用 # 运算符来字符串化,这样可以将参数转换为字符串。
  3. 宏定义中的参数可以使用 ## 运算符来拼接字符串,这样可以将两个参数拼接成一个新的字符串。
  4. 宏定义中的参数可以使用变参宏来接受可变数量的参数。

总之,宏扩展是C语言中非常重要的一种预处理技术,它可以帮助开发人员简化代码、提高可读性和可维护性。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

【为正名】99%人都不知道的##里用法

【"##"的官方“里”用法】 ---- “##”还有一个很少为人所知的“里”用法,在介绍它之前,不得不首先说说由ANSI-C99标准引入的另外一个参数扩展——可变参数。...只能放在参数形参列表的最后; 当用户的参数个数超过了规定的参数个数时,所有多出来的内容会一股脑的由“__VA_ARGS__”所背负; 当用户的参数个数正好等于形参的个数时,"__VA_ARGS__"就等效于一个空字符串...",##__VA_ARGS__",如果__VA_ARGS__是一个空字符串,则前面的","会一并被删除掉。...结合__VA_ARGS__的特性,我们可以写出类似这样的: #define EXAMPLE(......) ( 默认值 ,##__VA_ARGS__) 它有两种使用情况情况: 当我们使用参数的时候在括号里不填写任何内容,最终会展开为仅有默认值的情况: EXAMPLE(); 被展开为: ( 默认值

2.4K20

太强大了!源码面前了无秘密,手把手写个闭包

1.1 闭包基础 在libco中,所有的闭包实现是,先学习一下给函数传递的参数个数如何推断出来,怎么可以做到。...具体对应到展开如下:conac_argc传递一包参数给cnt,cnt将(0,一包参数,7,6,5,4,3,2,1,0),传递给comac_arg_n,在这个中进行替换,我们得到了 0,arg1,...1.2 co_ref展开 co_ref展开为: #define co_ref( name,... )\ repeat( comac_argc(__VA_ARGS__) ,decl_typeof,__...__ ) 依次调用下面: (1)参数个数计算 #define comac_get_args_cnt( ... ) comac_arg_n( __VA_ARGS__ ) #define comac_arg_n...(2)根据参数个数调用对应的repeat_x #define repeat_0( fun,a,... ) #define repeat_1( fun,a,... ) fun( 1,a,__VA_ARGS

76420

变参函数和可变参数

GNU 通过 attribute 扩展的 format 属性,用来指定变参函数的参数格式检查。...其实,C99 标准已经支持了这个特性,但是其它的编译器不太给力,对 C99 标准的支持 不是很好,只有 GNU C 支持这个功能,所以有时候我们也把这个可变参数看作是 GNU C 的一个语法扩展。...72.连接符##的作用 如果这个没有## #define LOG(fmt, ...) printf(fmt, __VA_ARGS__) 在这个定义中,有一个固定参数,通常为一个格式字符串,后面的变参用来打印各种格式的数据...而上面这种格式是 GNU C 扩展的一个新写法。我们不再使用 VA_ARGS ,而是直接使用 args... 来表示一个变参列表,然后在后面的定义中,直接使用 args 代表变参列表就可以了。...CONNECT(0x, __VA_ARGS__) 怎么实现的重载呢?

1.8K20

【为正名】什么?我忘了去上“数学必修课”!

在前面的文章《【为正名】本应写入教科书的“世界设定”》中我们了解到:会在预编译阶段被“处理掉”——会被逐级展开、其最终代表的字符串会被替换到对应的文本文件中(只不过通常这个文本文件就是".c"文件...答案是肯定的——GCC扩展的预编译语法提供了一个专门的,叫做 __COUNTER__——真可谓踏破铁鞋无觅处,蓦然回首,他就在灯火阑珊处——对每个编译的目标文件来说,__COUNTER__的初值是0,...) \ __ADD_FINAL_ITEM(__NAME, __VA_ARGS__) 为了方便隐藏定义枚举的“小动作”,我们追加了一对...(__VA_ARGS__) /*part2*/ 当用户使用CONNECT()时,VA_NUM_ARGS(__VA_ARGS__)会给出参数的数量...吸收掉,不会产生任何后果 VA_NUM_ARGS() 的巧妙在于,它把__VA_ARGS__放在了参数列表的最前面,并随后传递了 "9,8,7,6,5,4,3,2,1" 这样的序号: 当__VA_ARGS

65820

cc++:for each遍历 __VA_ARGS__ 中的每一个元素

typedef enum test{ test_1,test_2,test3.... }test; 手工写实在太多了,而且容易出错,于考虑用可变参数:__VA_ARGS__ 来实现,关键就是要实现对...下面是现实代码,真正调用的只有一个FL_FOREACH, FL_FOREACH实现对__VA_ARGS__中的每个参数执行指定的函数fun,fun允许有一个外部输入参数funarg 类似于C++...11 STL库中的for_each函数 代码中用到的FL_ARG_COUNT参见前一篇博客《c/c++:计算可变参数 __VA_ARGS__ 的参数个数》 // 参数拼接 #define FL_CONCAT...,fun,funarg,...) \ FL_FOREACH_(sepatator,fun,funarg,__VA_ARGS__) // 为动态参数 __VA_ARGS__ 每一个参数调用 fun ...,最大支持64个参数 // sepatator 分隔符 // fun 函数 // funarg 函数的参数 有了FL_FOREACH,就可以实现前述的需求了: #define enum_elem(p

1.9K10

整理CC++的可变参数

直到C99编译器标准,它允许可以定义可变参数(variadic macros) C可变参数 可变参数: #define DEBUG(...) printf(__VA_ARGS__) /* 在1999...年版本的ISO C 标准中 */ #define LOG(format, ...) fprintf (stderr, format, __VA_ARGS__) ...代表一个变化的参数表 __VA_ARGS...__用来把参数传递给,当被调用展开时,实际的参数就传递给了printf()....fprintf(stderr, format, ## __VA_ARGS__) 如果传入的可变参数被忽略或者为空时,##操作会将使得预处理器(preprocessor)去除掉它前面的逗号。...并且可以发现printf的实现为什么一定需要%s,%d等这种格式化字符串是为了给va_*两点关键信息:1.可变参数的个数(百分号的个数);2.可变参数的类型(%s,%d等) 不过C++作为扩展C,当然克服了这些限制

5.4K00

spdlog 日志库学习,简易封装

(strrchr(__FILE__, '/') + 1):__FILE__) #endif //定义一个在日志后添加 文件名 函数名 行号 的定义 #ifndef suffix #define suffix...to_string(__LINE__)).append("\"").append(msg).c_str() #endif 这种文件行号之类的 spdlog 本身也自带,可以参见 SPDLOG_LOGGER_CALL 定义...,用这个还得加上: #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE 不过它自带的函数用的 __FUNCTION__ 在 VS 下会显示类名,我自定义改成了...代码如下: #pragma once //定义使输出文件名和行号 #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE #define SPDLOG_TRACE_ON...(strrchr(__FILE__, '/') + 1):__FILE__) #endif //定义一个在日志后添加 文件名 函数名 行号 的定义 #ifndef suffix #define suffix

1.1K30
领券