news 2026/7/10 22:44:20

C语言如何实现C++的默认参数方法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C语言如何实现C++的默认参数方法

前言

在C++里,在声明一个函数时可以显示给参数指定默认参数值:

voidadd(inta,intb=2)

这样你直接调用add(1)编译器在构建的时候会默认给第二个参数传递2,但是C语言没有这样的能力,C语言是一个面向底层的语言,它不具备那么多花里胡哨的特性,但是我们可以通过宏的方法来实现,C语言里宏给我们提供了极大的灵活性开发,特别是在Linux、Zephyr这样的操作系统里经常会使用到宏来包装实现API。

宏的可变参数计算方法

我记得很久之前我看到过Zephyr的一段源码,它为unit test提供的一套API,是经过宏包装的,主要功能是通过宏来指定数量来生成指定数量级的测试函数,例如一个宏展3个Test函数,不需要自己去手写多个,其目的是为了测试一个API传递多个递阶数,所以这里先讲解一下如何利用宏来实现可变参数计算方法。
首先可以先看一段代码,这段代码是我最近为项目设计的日志模块所编写的,这里我简化了一下它的实现,目的是为了教学如何通过宏计算可变参数:

#defineFAST_LOG_PRINT_NUMBER(_0,_1,_2,_3,_4,_n,...)_n#defineFAST_LOG_MERG(...)FAST_LOG_PRINT_NUMBER(_,##__VA_ARGS__,\4,3,2,1,0)#defineFAST_LOG_CART_TRUE(a,b)a##b#defineFAST_LOG_CART(a,b)FAST_LOG_CART_TRUE(a,b)#defineFAST_LOG_PRINT(...)FAST_LOG_CART(FAST_LOG_PRINT_,\FAST_LOG_MERG(__VAR_ARGS__))(__VAR_ARGS__)#defineFAST_LOG_PRINT_0()//0#defineFAST_LOG_PRINT_1(_1)//1#defineFAST_LOG_PRINT_2(_1,_2)//2#defineFAST_LOG_PRINT_3(_1,_2,_3)//3#defineFAST_LOG_PRINT_4(_1,_2,_3,_4)//4

这个宏计算最大支持4个参数传递同时也支持传递空参数,那么接下来来说一下这一段的实现原理,其核心函数就两个:

FAST_LOG_PRINT_NUMBER(_0,_1,_2,_3,_4,_n,...)_nFAST_LOG_MERG(...)FAST_LOG_PRINT_NUMBER(_,##__VA_ARGS__,\4,3,2,1,0)

FAST_LOG_MERG输入的是可变参数,然后将__VA_ARGS__传递给FAST_LOG_PRINT_NUMBER,这个函数是推导宏,推导出有几个参数然后决定使用哪个FAST_LOG_PRINT,这里推导的思路也非常简单,FAST_LOG_MERG最终只输出_n,而FAST_LOG_MERG在调用FAST_LOG_PRINT_NUMBER的时候,假如给的是FAST_LOG_PRINT_NUMBER(0, 1, 2),那么最终宏翻译就是:FAST_LOG_PRINT_NUMBER(_, 0, 1, 2, 4, 3, 2) 2
最终这里的_n就变成了2,这里其实就是利用一个巧妙的挤数字方法,因为FAST_LOG_PRINT_NUMBER里面__VA_ARGS__后面紧跟着顺序数字依次递减,当__VA_ARGS__参数越多,后面的数字递增到N的就越大,这样就能计算出到底有多少个参数了。
其中最前面的__,这个是为了解决0参数时候也就是调用宏不给参数时默认给一个0,让_n这个数字变为0。
那么通过这个实现我们就可以实现给默认缺省参数了,在FAST_LOG_PRINT_0、FAST_LOG_PRINT_1、FAST_LOG_PRINT_2调用不同函数时来依次传递不同参数,例如有一个set_sys_config的api,可以封装为:
FAST_LOG_PRINT_0() set_sys_config(a, b, c, d)
#define FAST_LOG_PRINT_1(_1) set_sys_config(_1, a, b, c)
在调用时只需要调用FAST_LOG_PRINT即可:
FAST_LOG_PRINT(); //无参数
FAST_LOG_PRINT(“hello world”); //1个参数
这样就实现类似c++的缺省参数,其实这个方法在Linux/zephyr里也有用过,不过不是用于缺省,缺省只是这种开发方法应用场景的其中一个,在内核里多数用于例如写test case,要写许多非常多的重复代码,那么这个时候就可以利用这种方法来动态生成不同参数级别的test case func。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/10 22:39:11

彻底搞懂 K8s 服务访问:ClusterIP、NodePort 流量机制

前言在 Kubernetes 集群中,Pod 是最小的部署单元,但 Pod 的生命周期是短暂的——当 Pod 发生故障或被重新调度时,其 IP 地址也会随之改变。这就带来一个问题:如果一组 Pod 需要对外提供稳定服务(例如 HTTP 服务&#x…

作者头像 李华
网站建设 2026/7/10 22:35:48

Python深入浅出:从入门到工程实践13

第 13 章:并发基础:线程与进程 学习目标: 彻底理解 GIL 对 Python 并发的影响 掌握 threading 和 multiprocessing 的正确用法 能根据场景选择并发模型 13.0 为什么需要并发?——从现实问题出发 想象你在运营一个电商网站,需要完成以下任务: 任务 单线程耗时 说明 查询…

作者头像 李华
网站建设 2026/7/10 22:35:01

sc结构模块图中模块之间的关系(耦合、内聚)

耦合和内聚就是描述sc结构模块图中模块之间的关系 完全正确 内聚:描述单个模块内部元素联系紧密程度耦合:描述多个模块之间相互依赖关联程度 二者都是用来评判SC模块结构图设计好坏的核心指标 一、内聚(管自己) 定义 一个模块内部…

作者头像 李华
网站建设 2026/7/10 22:34:57

顶背离(Bearish Divergence)

顶背离(Bearish Divergence) 是技术分析里经典的见顶 / 反转预警信号:价格创新高,但动能指标(MACD/RSI/KDJ)不创新高、反而走低,说明上涨动能衰竭、多头乏力,大概率要回落。一、核心…

作者头像 李华
网站建设 2026/7/10 22:31:42

社群死群多?wechatapi iPad协议硬核破局

兄弟们,搞私域最怕啥?不是没流量,是流量进来后社群秒变僵尸群、广告群。多少老哥砸钱建群,最后群友全潜水,管理员累成狗,ROI直接崩盘。今天咱们就聊聊社群运营的硬核技术解法,用wechatapi的iPad…

作者头像 李华