[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 ...
随机推荐
- 深入理解Python异步编程(上)
本文代码整理自:深入理解Python异步编程(上) 参考:A Web Crawler With asyncio Coroutines 一.同步阻塞方式 import socket def blocki ...
- error.c
#include <stdio.h> #include <errno.h> #include <stdlib.h> #include <string.h> ...
- Javaweb学习笔记——(二十二)——————文件上传、下载、Javamail
文件上传概述 1.文件上传的作用 例如网络硬盘,就是用来上传下载文件的. 在网络浏览器中,时常需要上传照片 2.文件上传对页面的要求 上 ...
- 三、文件IO——系统调用(续)
3.2.4 read 函数--- 读文件 read(由已打开的文件读取数据) #include<unistd.h> ssize_t read(int fd, void * buf, siz ...
- ES6 快速开始
Refs 现代框架 Vue React 都使用到了 ES6 (包括D3js) [常量] // ES5 中常量的写法 Object.defineProperty(window, "PI2&qu ...
- zookeeper客户端 zkCli使用及常用命令
上篇(http://www.cnblogs.com/yangzhenlong/p/8270835.html)zk伪集群搭建好后,使用zkCli连接zk服务 切换到zk1/bin 目录,执行zkCli. ...
- 关于Java 实现抽象类的抽象方法的特性的利用---面向切面
今天看工作看代码突然有了以下设想: /** * Created by zq on 2017/5/25. * 抽象类 */ public abstract class AbstractC { publi ...
- 深度学习 ——style reconstruction
多层神经网络的实质就是为了找出更复杂,更内在的features...图像的style, how to describe, impossible! 但是人眼却可以分辨. (参考论文 A Neural a ...
- Web获取客户端物理MAC地址(ocx插件)ActiveX控件
主要是通过ActiveX控件 从本地获取到MAC地址,传入到浏览器打开的网页中,再提交到服务器. 具体详解与步骤看文档中: 文件实例包下载 DotNetFX 文件夹附件文件:(可能安装时需用) dot ...
- Linux LVM 逻辑分区
LVM是 Logical Volume Manager(逻辑卷管理)的简写,它是Linux环境下对磁盘分区进行管理的一种机制,它由Heinz Mauelshagen在Linux 2.4内核上实现.普通 ...