C 库函数:va_list、va_start、va_end 和 vprintf 的用法

总结一下C语言项目中不定参数相关的va_list、va_start、va_end和va_arg四个宏的用法。
c语言提供了函数的不定长参数使用,比如 void func(int a, …)。三个省略号,表示了参数a后跟着不定长参数。注意:c标准规定了,函数必须至少有一个明确定义的参数,因此,省略号前面必须有至少一个参数,这个参数用于定位之后的不定参数从这里之后开始的。
va_list宏定义了一个指针类型变量,这个指针类型指向参数列表中的参数(不定参的起始位置)。
void va_start(va_list ap, last_arg),修改了用va_list申明的指针,比如ap,使这个指针指向了不定长参数列表省略号前的位置(即:第一个不定的位置)。
type va_arg(va_list, type),获取参数列表的下一个参数,并以type的类型返回。这里有坑!!!
void va_end(va_list ap), 参数列表访问完以后,参数列表指针与其他指针一样,必须收回,否则出现野指针。一般va_start 和va_end配套使用。
函数的参数一般从右至左先后入栈,根据栈的特性,也就是,最左边的参数最先出栈。贴一段代码介绍下va_list、va_start和va_end的使用。

示例:

下图将四个float型变量传入func_test(),测试这几个宏的用法。首先,执行完va_start后,变量argpointer指向了变量float a的地址,(抱歉,被csdn水印挡住了);

在这里插入图片描述

紧接着,vprintf函数获取了从a开始的变量,按照pszfmt定义的格式化方式,打印了出来;然后,当执行一次va_arg后,argpointer的指针又指向了b所在的地址,看红色标记。

描述
C 库函数 int vprintf(const char *format, va_list arg) 使用参数列表发送格式化输出到标准输出 stdout。

其实printf和scanf一系列,有很多函数

int printf(const char *format, …);
int fprintf(FILE *stream, const char *format, …);
int sprintf(char *str, const char *format, …); //写到指定数组
int snprintf(char *str, size_t size, const char *format, …);

int vprintf(const char *format, va_list ap);
int vfprintf(FILE *stream, const char *format, va_list ap);
int vsprintf(char *str, const char *format, va_list ap);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);

int scanf(const char *format, …);
int fscanf(FILE *stream, const char *format, …);
int sscanf(const char *str, const char *format, …);

int vscanf(const char *format, va_list ap);
int vsscanf(const char *str, const char *format, va_list ap);
int vfscanf(FILE *stream, const char *format, va_list ap);

在这里插入图片描述

最后,不出所料,打印后期出问题了,这就是因为这几个宏无法知道不定参数到底有几个,一直执行他会一直往后读。就是前边所说的坑。那解决办法是怎样的?

在这里插入图片描述
把代码改成了这个样子的:

#include <Windows.h>
#include <stdio.h>
#include <stdarg.h>
void func_test(int num, char*, ...);
int main()
{
	float a = 1.2;
	float b = 1.3;
	float c = 1.4;
	float d = 1.5;

	func_test(4, "a=%.2f\tb=%.2f\tc=%.2f\td=%.2f\n", a,b,c,d);
	return 0;
}
void func_test(int num, char* pszfmt, ...)
{
	va_list argpointer;
	va_start(argpointer, pszfmt);
	//格式化打印输出
	int ret = vprintf(pszfmt, argpointer);

	float argument;
	int count = 0;
	while (count < num)
	{	
		argument = ((float)va_arg(argpointer, double));
		printf("parameter %d  : %.2f \n", ++count, argument);
	}
	system("pause");
}

在这里插入图片描述
参考博客:
https://blog.csdn.net/hust_joker/article/details/82855627?utm_medium=distribute.pc_relevant_download.none-task-blog-baidujs-1.nonecase&depth_1-utm_source=distribute.pc_relevant_download.none-task-blog-baidujs-1.nonecase
https://blog.csdn.net/pang123hui/article/details/6003513
https://blog.csdn.net/qq_40732350/article/details/82594741

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值