一、概述

运用标准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. 几本不错的数据仓库和Hadoop书籍

    <<Pentaho Kettle解决方案:使用PDI构建开源ETL解决方案>>, Matt Casters等著,初建军翻译<<Hadoop应用架构>> ...

  2. Sqlserver直接附加数据库和设置sa密码

    1.exec sp_attach_db 'test','E:\db\test.mdf','E:\db\test_log.ldf' 2.sp_password Null,'123','sa' 推荐一个微 ...

  3. 【八】Spring Cloud Config

    一.分布式系统面临的--配置问题 微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的力度相对较小,因此系统中会出现大量的服务.由于每个服务都需要必要的配置信息才能运行,所以一套集中式的.动 ...

  4. 微信小程序开发(3) 热门电影

    在这篇微信小程序开发教程中,我们将介绍如何使用微信小程序开发热门电影及预览功能. 本文主要分为两个部分,小程序主体部分及电影主页和详情页页面部分 一.小程序主体部分 一个小程序主体部分由三个文件组成, ...

  5. Javaweb学习笔记——(二十)——————Javaweb监听器、国际化

    Javaweb监听器     三大组件         *Servlet         *Listener         *Filter Listener:监听器         1.初次相见:A ...

  6. 测试四则运算2:Right-BICEP

    n6个值得测试的具体部位,他们能够提高你的测试技巧 nRight-结果是否正确? nB-是否所有的边界条件都是正确的? nI-能查一下反向关联吗 nC-能用其他手段交叉检查一下结果吗? nE-你是否可 ...

  7. Coursera, Deep Learning 2, Improving Deep Neural Networks: Hyperparameter tuning, Regularization and Optimization - week1, Course

    Train/Dev/Test set Bias/Variance Regularization  有下面一些regularization的方法. L2 regularation drop out da ...

  8. 微信小程序总结

    一.基础用法: <navigator url='跳转页面组件'></navigator>用法和a标签差不多 <text></text>文本标签 < ...

  9. 【blog】用emoji-java解决Emoji存储MySQL乱码问题

    emoji-java 核心方法: EmojiParser.parseToAliases(string); 将表情符号转为字符 EmojiParser.parseToUnicode(string); 将 ...

  10. MGR架构~ 整体性能架构的调优

    一 简介:MGR集群架构的调优二 过程:本文将从各个角度来具体阐述下三 硬件    1 硬件选择相同配置的服务器,磁盘,内存,cpu性能越高越好四 网络    1 0丢包和最好万兆网卡五 MGR本身  ...