va_list/va_start/va_end/va_arg、printf的实现及其家族

博客先介绍了调用函数时实参入栈方式,讲解了stdarg.h中va_list、va_start、va_arg、va_end的定义和作用,如va_list本质是字符指针,va_start使入参指向第一个变参地址等,还给出相关地址介绍的参考博客,最后提及用这些方法实现printf但未测试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.va_list等

先了解一下调用函数时,实参入栈的方式
在这里插入图片描述
stdarg.h中的定义

#inclde<stdarg.h>
typedef char *va_list;
#define va_start(list,param1)   ( list = (va_list)&param1+ sizeof(param1) )
#define va_arg(list,mode)   ( (mode *) ( list += sizeof(mode) ) )[-1]
#define va_end(list) ( list = (va_list)0 )
  • va_list:本质上就是一个字符指针
  • va_start
    使入参list指向第一个变参的地址。注意!!不是第一个参数,如上printf()的例子,a是第一个变参,而不是一开始的那个字符。以上面的例子解释:
 	(va_list)&param1 = (char *)0
 	sizeof(param1) = sizeof(char *) = 4
 	list = 0 + 4 = 4
 	此时,list里存放的是变量a的地址
  • va_arg:
    实现:返回此时list指向的变参,并且让list指向下一个变参
	按结合律来分析,首先执行的是
	list += sizeof(mode)
	意思就是list指向了下一个变量,因为加的是 本次指向的变量 的类型
	(mode *) ( list += sizeof(mode) )
	再把改变之后的值变为 指向刚刚的变量 的类型指针
	后面有一个[-1],就代表返回的是 刚刚指向的变量

上面讲的太混乱,结合例子看

	假设此时list = 4,即目前刚刚执行完 va_start(list,format) 这一句,一个变参还没有使用时
	执行 int *a = va_arg(list,int); 因为我知道第一个变参是int型,所以这里才直接这么写,如果不知道变参类型是不能用的
	list += sizeof(int);  ==>list=8;  此时list就变成了8
	(int)list == list(8) ;8变成了int型的地址,也就是说接下来对8自加或者自减,都是加减4
	list[-1];     这句就类似于数组了,数组中括号表示的是第几个元素,但是数组中没有负数
				  而如果是指针的话,就可以有负数,-1表示该种类型前一个地址,即地址减减
				  int 型地址8减减,就是4
	所以最终,这个宏返回的是int型地址4,即第一个变参a的地址,而此时的list中存的已经是变参b的地址

va_end:
这个就是把第一开始定义的list变量,指向NULL,防止野指针
关于地址 后[-1]的介绍,可以参考一下以下博客
http://www.dengb.com/Cyy/1347567.html

printf家族及printf的实现

int vprintf / vscanf(const char * format, va_list ap); // 格式化format到标准输出
int vfprintf / vfsacanf(FILE * stream, const char * format, va_list ap); // 格式化format到stream文件
int vsprintf / vsscanf(char * s, const char * format, va_list ap); // 格式化format到字符串s

用以上三种方法实现printf(自己写的,还没测试)

//vprintf实现
int printf(const char * format, ...)
{
	int iNum;
	
	va_list list;
    va_start(list,format);
    iNum = vprintf(format , list);
    va_end(list);
    return iNum;
}
int printf(const char * format, ...)
{
	int iNum;
	
	va_list list;
    va_start(list,format);
    iNum = vfprintf(stdin,format , list); //stdin是FILE *; STDOUT_FILENO是整形的文件句柄
    va_end(list);
    return iNum;
}
int printf(const char * format, ...)
{
	char buff[1000];
	int iNum;
	
	va_list list;
    va_start(list,format);
    iNum = vsprintf(buff ,format , list); //返回一共多少个字符
    va_end(list);
    buff[iNum] = '\0'  					//加上截至符
    write(STDOUT_FILENO , buff , strlen(buff));
    return iNum;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值