一、概述

运用标准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 shortshort 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可变长参数的使用的更多相关文章

  1. 可变长参数列表误区与陷阱——va_arg不可接受的类型

    可变长参数列表误区与陷阱--va_arg不可接受的类型 实现一个有可变长参数列表函数的时候,会使用到stdarg.h(这里不讨论varargs.h)中提供的宏. 例如,我们要实现一个简易的my_pri ...

  2. [转]深度探索C语言函数可变长参数

    转自:http://www.cnblogs.com/chinazhangjie/archive/2012/08/18/2645475.html 一.基础部分 1.1 什么是可变长参数 可变长参数:顾名 ...

  3. 关于C中可变长参数

    前言 可变长参数指函数的参数个数在调用时才能确定的函数参数.基本上各种语言都支持可变长参数,在特定情形下,可变长参数使用起来非常方便.c语言中函数可变长参数使用“...”来表示,同时可变长参数只能位于 ...

  4. C语言开发具有可变长参数的函数的方法

    学习交流可加 微信读者交流①群 (添加微信:coderAllen) 程序员技术QQ交流①群:736386324 --- 前提:ANSI C 为了提高可移植性, 通过头文件stdarg.h提供了一组方便 ...

  5. C++ 系列:函数可变长参数

    一.基础部分 1.1 什么是可变长参数 可变长参数:顾名思义,就是函数的参数长度(数量)是可变的.比如 C 语言的 printf 系列的(格式化输入输出等)函数,都是参数可变的.下面是 printf ...

  6. C语言之可变长参数格式化

    概述 本文演示环境: win10 + Vs2015 可变长参数格式化 两个概念: 1. 参数长度不定, 2. 参数格式化. 使用函数 vsnprintf 结合 va_list. 源码 写好了函数, 照 ...

  7. 在Python中使用可变长参数列表

    函数定义 在函数定义中使用*args和**kwargs传递可变长参数. *args用作传递非命名键值可变长参数列表(位置参数); **kwargs用作传递键值可变长参数列表 函数调用 在调用函数时,使 ...

  8. python中非关键字可变长参数和关键字变量参数的区别

    #非关键字可变长参数 def add(*arg):    return type(arg) print add() #打印结果 <type 'tuple'> #关键字变量参数 def ab ...

  9. Java中的可变长参数

    可变长参数的定义 与一般方法没多大差别,只不过形参多了...(三个点) 方法名(数据类型 ... 变量名){} 小案例: public class ParamDemo { public static ...

随机推荐

  1. React Native的语法之ES5和ES6

    原文地址:http://www.devio.org/2016/08/11/React-Native%E4%B9%8BReact%E9%80%9F%E5%AD%A6%E6%95%99%E7%A8%8B- ...

  2. javascript获取值

    <div id='name'>张三</div> $('#name').val() $(name).val() 以上两个都可以得到值,第一种用的比较多.

  3. Java实现猜数字,附带提示功能。

    很简单的一段代码: package com.changeyd.demo; import java.util.Random;import java.util.Scanner;public class M ...

  4. 二十二、Linux 进程与信号---进程创建

    22.1 fork 和 vfork 函数 22.1.1 函数说明 #include <unistd.h> #include <sys/types.h> pid_t fork( ...

  5. asp.net mvc 多文件上传

    @{ ViewBag.Title = "多文件上传测试"; } <h2>多文件上传测试</h2> <form action="/Demo/I ...

  6. 初识css预处理器:Sass、LESS

    这篇文章是初步介绍css预处理的,详细学习请移步官网~ 什么是css预处理器 CSS 预处理器是一种语言, 通俗易懂的话来说就是“用一种专门的编程语言,进行 Web 页面样式编写,再通过编译器转化为正 ...

  7. 【blog】SpringBoot如何搭建聚合项目

    以我的博客为例 blog --blog-common --blog-entity --blog-repo --blog-service --blog-web SpringBoot聚合项目推荐 http ...

  8. Android自定义控件三种方式

    1.组合原生控件(继承自ViewGroup.LinearLayout.FrameLayout.RelativeLayout等)   将原生空间做组合,自定义一些事件 2.自己绘制控件(继承自View) ...

  9. 前端必备——js中前端与后台的数据交互全解

    只要编程语言能够支持网卡端口的监听和发送,理论上都是可以实现服务器后台设计的.也因此造成了实现后台的语言偏多,而web前端语言以html/css/js为主.所以在这里我们不涉及后台的设计,只介绍在we ...

  10. android listView多层嵌套listView显示不全问题

    最近在做项目,需要用到listVIew多层嵌套listVIew的需求,先发现已下两个处理办法比较好用 第一种: public class ListViewNesting extends ListVie ...