[C]va_list可变长参数的使用
一、概述
运用标准C的头文件stdarg.h提供的宏可以实现函数的自定义传参个数;
二、语法
1.va_list是一个可变长参数类型,在使用可变长参数的函数中可以定义1个或多个va_list类型参数,等待va_start初始化后使用;
va_list parg_1;
va_list parg_2;
2.va_start作用是给va_list类型变量绑定一个起始值
宏原型:
void va_start(va_list ap, last);
ap是va_list类型变量;
last是函数的最后一个固定参数(由于可变长函数的声明语法,参数部分必须至少包含一个固定传参);
va_start执行后,该ap的指针将会指向变参的起始位置;
3.va_copy作用是复制一份初始化后的va_list变量,通常用在调用va_start之后;
void va_copy(va_list ap2, va_list ap1);
ap2是复制到达的va_list变量;
ap1是被复制的va_list变量;
复制完毕后,两个变量的变长参数偏移量不相干;
4.va_arg被调用后将会返回当前指针偏移量的参数,随之指针将会移动到下一个变参的位置
type va_arg(va_list ap, type);
ap是被初始化后的va_list变量;
type是,除以下类型之外的其他类型
type绝对不能为以下类型:
——char、signed char、unsigned char
——short、unsigned
short
——signed short、short int、signed short int、unsigned short int
——float
这是因为C标准中有一个默认参数提升(default argument promotions)规则。
注意:有时候因为代码问题(例如类型错误)导致va_arg返回了错误的结果,但是也不会影响va_arg的下一次取参哦,这是因为指针的偏移是通过变参的底层size属性获取的
5.va_end用于结束整个取参流程
void va_end(va_list ap);
二、示例
1.通过代码说明printf的原理
#include <stdio.h>
#include <string.h>
#include <stdarg.h> void myPrintf(const char *format, ...); int main(void)
{
char str_1[] = "January & February";
double d_1 = 0.25;
int i_1 = ;
char str_2[] = "March & April";
int i_2 = ;
myPrintf(str_1, d_1, i_1, str_2, i_2);
} void myPrintf(const char *format, ...)
{
printf("%s\n", format);
va_list parg;
va_start(parg, format);
printf("%.6lf\n", va_arg(parg, double));
printf("%d\n", va_arg(parg, int));
printf("%s\n", va_arg(parg, char*));
printf("%d\n", va_arg(parg, int));
va_end(parg);
}
输出:
0.250000
16
March & April
528
说明:
C自带的printf函数是根据第一个参数format的占位符解析出后面的变参个数和类型,通过va_arg迭代去获取变参再填充到占位符上输出。解析占位符并不是一件简单的工作,所以这里的代码只是大致说明了一下它的原理;
2.求平均数
#include <stdio.h>
#include <stdarg.h> double average(double v1, double v2, ...); int count = ; int main(void)
{
printf("Average = %.6lf\n", average(0.2, 3.5, 108.625, (double), 0.3, 0.0));
} double average(double v1, double v2, ...)
{
va_list parg;
double sum = v1 + v2;
double value = 0.0;
int count = ; va_start(parg, v2);
while((value = va_arg(parg, double)) != 0.0)
{
printf("Item = %.6lf\n", value);
sum += value;
++count;
}
va_end(parg);
return sum/count;
}
说明:
此代码在固定前两个参数的前提下,后面使用变参
[C]va_list可变长参数的使用的更多相关文章
- 可变长参数列表误区与陷阱——va_arg不可接受的类型
可变长参数列表误区与陷阱--va_arg不可接受的类型 实现一个有可变长参数列表函数的时候,会使用到stdarg.h(这里不讨论varargs.h)中提供的宏. 例如,我们要实现一个简易的my_pri ...
- [转]深度探索C语言函数可变长参数
转自:http://www.cnblogs.com/chinazhangjie/archive/2012/08/18/2645475.html 一.基础部分 1.1 什么是可变长参数 可变长参数:顾名 ...
- 关于C中可变长参数
前言 可变长参数指函数的参数个数在调用时才能确定的函数参数.基本上各种语言都支持可变长参数,在特定情形下,可变长参数使用起来非常方便.c语言中函数可变长参数使用“...”来表示,同时可变长参数只能位于 ...
- C语言开发具有可变长参数的函数的方法
学习交流可加 微信读者交流①群 (添加微信:coderAllen) 程序员技术QQ交流①群:736386324 --- 前提:ANSI C 为了提高可移植性, 通过头文件stdarg.h提供了一组方便 ...
- C++ 系列:函数可变长参数
一.基础部分 1.1 什么是可变长参数 可变长参数:顾名思义,就是函数的参数长度(数量)是可变的.比如 C 语言的 printf 系列的(格式化输入输出等)函数,都是参数可变的.下面是 printf ...
- C语言之可变长参数格式化
概述 本文演示环境: win10 + Vs2015 可变长参数格式化 两个概念: 1. 参数长度不定, 2. 参数格式化. 使用函数 vsnprintf 结合 va_list. 源码 写好了函数, 照 ...
- 在Python中使用可变长参数列表
函数定义 在函数定义中使用*args和**kwargs传递可变长参数. *args用作传递非命名键值可变长参数列表(位置参数); **kwargs用作传递键值可变长参数列表 函数调用 在调用函数时,使 ...
- python中非关键字可变长参数和关键字变量参数的区别
#非关键字可变长参数 def add(*arg): return type(arg) print add() #打印结果 <type 'tuple'> #关键字变量参数 def ab ...
- Java中的可变长参数
可变长参数的定义 与一般方法没多大差别,只不过形参多了...(三个点) 方法名(数据类型 ... 变量名){} 小案例: public class ParamDemo { public static ...
随机推荐
- SQL 编程技巧
Ø 简介 本文主要介绍编写 SQL 时的一些编程技巧,方便有时候忘了便于查看,主要包含以下内容: 1. SQL 语句中使用 +=.-=.*=./= 运算符 2. 值为 NULL 的列或局部变 ...
- 二十四、Linux 进程与信号---wait 函数
24.1 wait 函数说明 24.1.1 waitpid---等待子进程中断或结束 waitpid(等待子进程中断或结束) 相关函数 wait,fork #include <sys/types ...
- mysql 约束和外键约束实例
1.约束保证数据的完整性和一致性. 2.约束分为表级约束和列级约束.(根据约束所针对的字段的数目的多少来决定) 列级约束:对一个数据列建立的约束 表级约束:对多个数据列建立的约束 列级约束即可以在列定 ...
- ES6走一波 Generator异步应用
Generator 函数的异步应用 JS异步编程 callback Promise(解决回调地狱) 事件 发布订阅 generator Thunk函数 屁股函数 两次高阶调用的函数 第一次调用的入参 ...
- $(function() {....}) ,(function($){...})(jQuery)
$(function() {....}) 是 jQuery 中的经典用法,等同于 $(document).ready(function() {....}),即在页面加载完成后才执行某个函数,如果函数中 ...
- 【数据表格】datatable+SpringMVC+Spring Data JPA
初步实现 $("#userTable").dataTable({ "processing": true, "serverSide": tru ...
- Path for IClasspathEntry must be absolute:
关掉eclipse, 删除workspace工作目录下面的.metadata文件,看不到.metadata文件就 "ctril + H" 就可以看到了.然后重新打开eclipse, ...
- Java-Servlet -Helloworld
Servlet 简介 Servlet是sun公司提供的一门用于开发动态web资源的技术. Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏 ...
- LightOJ - 1245 Harmonic Number (II) 求同值区间的和
题目大意:对下列代码进行优化 long long H( int n ) { long long res = 0; for( int i = 1; i <= n; i++ ) ...
- 如何在vue中使用动态使用本地图片路径
不知道各位小伙伴有没有在开发遇到一个问题,就是在线上的项目使用后台返回本地图片路径,然后加载不上的情况呢? 我的解决方法就是:先在项目的data下定义好这样一个数组用于存放需要加载的路径 [ {nam ...