可变参数列表源码分析及函数设计

本文深入解析C语言中可变参数的实现原理,包括stdarg.h头文件的使用,va_list、va_start、va_arg和va_end宏的详细解释,以及如何模拟实现printf函数。通过实例演示如何求不同个数的平均数,揭示了可变参数列表的访问规则和限制。

目录

一、什么是可变参数?

二、可变参数的实现

三、可变参数源码

四、模拟实现printf函数


一、什么是可变参数?

    可变参数是一个比较有意思的实现,通过将函数实现为可变参数的形式,可以使得函数可以接受1个以上的任意多个参数。      

    一般情况下,我们写的函数参数的数目是固定不变的,调用函数时要给出相应的实参,但有些时候,为了做同样的事情,由于参数个数不同,我们总不能写很多个函数,这就有点冗余了。比如:我们想求两个数或10个数的平均数,可以用同一个函数实现。

二、可变参数的实现

C语言头文件stdarg.h中提供了一个va_list的数据类型和va_start,va_arg,va_end三个宏

        1.声明一个 va_list 类型的变量 arg ,它用于访问参数列表的未确定部分。
        2.这个变量是调用 va_start 来初始化的。它的第一个参数是 va_list 的变量名,第2个参数是省略号前最后一个有名字的参数。初始化过程把 arg 变量设置为指向可变参数部分的第一个参数。
        3.为了访问参数,需要使用 va_arg ,这个宏接受两个参数: va_list 变量和参数列表中下一个参数的类型。在这个例子中所有的可变参数都是整型。va_arg````返回这个参数的值,并使用 va_arg```指向下一个可变参数。
        4.最后,当访问完毕最后一个可变参数之后,我们需要调用 va_end 。

举例:求不同个数的平均数

int avg(int n, ...)
{
	va_list arg;
	va_start(arg, n);//arg指向可变参数的第一个参数
	int sum = 0;
	for (int i = 0; i < n; i++)
	{
		sum += va_arg(arg, int);//返回该参数的值并自动指向下一个参数
	}
	va_end(arg);
	return sum / n;
}
int main()
{
	int a = 1, b = 2, c = 3,d=10;
        printf("%d\n", avg(4,a, b, c,d));
	printf("%d\n", avg(2,a, c));
}

并不是所有的函数都可以使用可变参数列表,使用时要注意:

1>可变参数必须从头到尾逐个访问。如果在访问了几个可变参数之后想半途终止,这是可以的,但是,如果一开始就访问参数列

表中间的参数,那是不行的。

2>参数列表中至少有一个命名参数。如果连一个命名参数都没有,就无法使用va_start。

3>这些宏是无法直接判断实际存在参数的数量;这些宏无法判断每个参数类型。
 

三、可变参数源码

可变参数的实现过程是使用宏的封装。只要完成替换,就可以自行分析了。

1.va_list:是一种数据类型,可以说就是char*。

        typedef char* va_list;

2.va_start:初始化arg为未知参数列表的第一个参数的地址,va_start其实是一个宏函数,第一个参数是一个可以表示后面的参数个数和参数类型的char* ,第二个参数表示就是用于指明arg是指针名,n代表第一个参数,用于表示起始端。

  #define _INTSIZEOF(n)          ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1))

  #define _ADDRESSOF(v) (&(v))
  
  #define __crt_va_start_a(ap, v) ((void)(ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v)))

3.va_arg:返回当前参数再指向下一个参数。

 #define _INTSIZEOF(n)          ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1))

 #define __crt_va_arg(ap, t)     (*(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))

通过 va_arg(arg, int) 拿到后面的参数:

1.ap表示可变参数指针,而t表示数据类型。使用 ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1)) ,传入char,float,double等小于4字节的类型,都会返回4。如果类型大小是,5,6,7的话,则返回8。即返回当前一组数中靠近4的倍数的值。 

2.( (t )((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) 该表达式先让指针ap加上4字节的大小,再把减去4字节大小处所对应的值返回。用t强制类型转换,再解引用,此处 t是传入参数的数据类型。

4.va_end:结束。arg赋值为空指针。

  #define __crt_va_end(ap)        ((void)(ap = (va_list)0))

四、模拟实现printf函数

模拟实现printf函数,可完成下面的功能 
//能完成下面函数的调用。 
//print("s ccc d.\n","hello",'b','o','y',100); 
 

void print_num(int n)
{
	if (n > 9)
		print_num(n / 10);
	putchar(n % 10 + '0');
}
void print(const char* format, ...)
{
	va_list arg;
	va_start(arg, format);
	
	while (*format)
	{
		switch (*format)
		{
			case 's':
			{
				char *str = va_arg(arg, char*);
				while (*str)
				{
					putchar(*str);
					str++;
				}
			}
				break;
			case 'c':
			{
				char ch = va_arg(arg, char);
				putchar(ch);
			}
			break;
			case 'd':
			{
				int tmp = va_arg(arg, int);
				print_num(tmp);
			}
			break;
			default:
				putchar(*format);
				break;
		}
		format++;
	}
}

 

 

 

 

 

 

根据原作 https://pan.quark.cn/s/459657bcfd45 的源码改编 Classic-ML-Methods-Algo 引言 建立这个项目,是为了梳理和总结传统机器学习(Machine Learning)方法(methods)或者算法(algo),和各位同仁相互学习交流. 现在的深度学习本质上来自于传统的神经网络模型,很大程度上是传统机器学习的延续,同时也在不少时候需要结合传统方法来实现. 任何机器学习方法基本的流程结构都是通用的;使用的评价方法也基本通用;使用的一些数学知识也是通用的. 本文在梳理传统机器学习方法算法的同时也会顺便补充这些流程,数学上的知识以供参考. 机器学习 机器学习是人工智能(Artificial Intelligence)的一个分支,也是实现人工智能最重要的手段.区别于传统的基于规则(rule-based)的算法,机器学习可以从数据中获取知识,从而实现规定的任务[Ian Goodfellow and Yoshua Bengio and Aaron Courville的Deep Learning].这些知识可以分为四种: 总结(summarization) 预测(prediction) 估计(estimation) 假想验证(hypothesis testing) 机器学习主要关心的是预测[Varian在Big Data : New Tricks for Econometrics],预测的可以是连续性的输出变量,分类,聚类或者物品之间的有趣关联. 机器学习分类 根据数据配置(setting,是否有标签,可以是连续的也可以是离散的)和任务目标,我们可以将机器学习方法分为四种: 无监督(unsupervised) 训练数据没有给定...
本系统采用微信小程序作为前端交互界面,结合Spring Boot与Vue.js框架实现后端服务及管理后台的构建,形成一套完整的电子商务解决方案。该系统架构支持单一商户独立运营,亦兼容多商户入驻的平台模式,具备高度的灵活性与扩展性。 在技术实现上,后端以Java语言为核心,依托Spring Boot框架提供稳定的业务逻辑处理与数据接口服务;管理后台采用Vue.js进行开发,实现了直观高效的操作界面;前端微信小程序则为用户提供了便捷的移动端购物体验。整套系统各模块间紧密协作,功能链路完整闭环,已通过严格测试与优化,符合商业应用的标准要求。 系统设计注重业务场景的全面覆盖,不仅包含商品展示、交易流程、订单处理等核心电商功能,还集成了会员管理、营销工具、数据统计等辅助模块,能够满足不同规模商户的日常运营需求。其多店铺支持机制允许平台方对入驻商户进行统一管理,同时保障各店铺在品牌展示、商品销售及客户服务方面的独立运作空间。 该解决方案强调代码结构的规范性与可维护性,遵循企业级开发标准,确保了系统的长期稳定运行与后续功能迭代的可行性。整体而言,这是一套技术选型成熟、架构清晰、功能完备且可直接投入商用的电商平台系统。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值