c语言的可变参数实例
可变参数函数实现的步骤如下:
1.在函数中创建一个va_list类型变量
2.使用va_start对其进行初始化
3.使用va_arg访问参数值
4.使用va_end完成清理工作
接下来我们来实现一个变长参数函数来对给定的一组整数进行求和。程序清单如下:
#include <stdio.h>
/*要使用变长参数的宏,需要包含下面的头文件*/
#include <stdarg.h>
/*
* getSum:用于计算一组整数的和
* num:整数的数量
*
* */
int getSum(int num, ...)
{
va_list ap;//定义参数列表变量
int sum = 0;
int loop = 0;
va_start(ap, num);
/*遍历参数值*/
for (; loop < num ; loop++)
{
/*取出并加上下一个参数值*/
sum += va_arg(ap, int);
}
va_end(ap);
return sum;
}
int main(int argc, char *argv[])
{
int sum = 0;
sum = getSum(5, 1, 2, 3, 4, 5);
printf("%d\n", sum);
return 0;
}
上面的小程序接受变长参数,第一个参数表明将要计算和的整数个数,后面的参数是要计算的值。
编译运行可得结果:15。
总结
通过前面的分析和示例,我们来做一些总结
变长参数实现的基本原理
对于x86来说,函数参数入栈顺序为从右往左,因此,在知道第一个参数地址之后,我们能够通过地址偏移获取其他参数,虽然x86-64在实现上略有不同,但`对于开发者使用来说,实现变长参数函数没有32位和64位的区别。变长参数实现注意事项
1.…前的参数可以有1个或多个,但前一个必须是确定类型。
2.传入参数会可能会出现类型提升。
3.va_arg的type类型不能是char,short int,float等类型,否则取值不正确,原因为第2点。
4.va_arg不能往回取参数,但可以使用va_copy拷贝va_list,以备后用。
5.变长参数类型注意做好检查,例如可以采用printf的占位符方式等等。
6.即便printf有类型检查,但也要注意参数匹配,例如,将int类型匹配%s打印,将会出现严重问题。
7.当传入参数个数少于使用的个数时,可能会出现严重问题,当传入参数大于使用的个数时,多出的参数不会被处理使用。
8.注意字节对齐问题。
变长参数实现
经过前面的理解分析,我们知道,正是由于参数从右往左入栈(但是要注意的是,对于x86-64,它的参数不是完全从右往左入栈,且参数可能不在一个连续的区域中,它的变长参数实现也更为复杂,我们这里不展开)可以实现变长参数。当然了,这一切,C已经有现成可用的一些东西来帮我们实现变长参数。
它主要通过一个类型(va_list)和三个宏(va_start、va_arg、va_end)来实现
va_list :存储参数的类型信息,32位和64位实现不一样。
void va_start ( va_list ap, paramN );
参数:
ap: 可变参数列表地址
paramN: 确定的参数
功能:初始化可变参数列表,会把paraN之后的参数放入ap中
type va_arg ( va_list ap, type );
功能:返回下一个参数的值。
void va_end ( va_list ap );
功能:完成清理工作。
转载自:
https://mp.weixin.qq.com/s/CbXT6G0CHzp0BG0gS-hprw
#include <stdio.h>
#include <stdarg.h>
#include <math.h> double sample_stddev(int count, ...)
{
/* Compute the mean with args1. */
double sum = 0;
va_list args1;
va_start(args1, count);
va_list args2;
va_copy(args2, args1); /* copy va_list object */
for (int i = 0; i < count; ++i)
{
double num = va_arg(args1, double);
sum += num;
}
va_end(args1);
double mean = sum / count; /* Compute standard deviation with args2 and mean. */
double sum_sq_diff = 0;
for (int i = 0; i < count; ++i)
{
double num = va_arg(args2, double);
sum_sq_diff += (num - mean) * (num - mean);
}
va_end(args2); return sqrt(sum_sq_diff / count);
} int main(void)
{
printf("%f\n", sample_stddev(4, 25.0, 25.0, 25.0, 25.0)); return 0;
}
这个是va_copy的函数用法,
c语言的可变参数实例的更多相关文章
- C语言的可变参数在Linux(Ubuntu)与Windows下注意点
基本上C语言的可变参数原理在不同平台和不同编译器下基本类似(通过函数入栈,从右向左,从高位到低位地址),不过部分实现会有所不同:在使用中需要注意的是: va_list 为char 类型指针,部分调用如 ...
- C语言中可变参数的函数(三个点,“...”)
C语言中可变参数的函数(三个点,“...”) 本文主要介绍va_start和va_end的使用及原理. 在以前的一篇帖子Format MessageBox 详解中曾使用到va_start和va_end ...
- [11 Go语言基础-可变参数函数]
[11 Go语言基础-可变参数函数] 可变参数函数 什么是可变参数函数 可变参数函数是一种参数个数可变的函数. 语法 如果函数最后一个参数被记作 ...T ,这时函数可以接受任意个 T 类型参数作为最 ...
- C语言中可变参数的使用
在C语言程序编写中我们使用最多的函数一定包括printf以及很多类似的变形体.这个函数包含在C库函数中,定义为 int printf( const char* format, ...); 除了一个格式 ...
- C语言中可变参数函数实现原理
C函数调用的栈结构 可变参数函数的实现与函数调用的栈结构密切相关,正常情况下C的函数参数入栈规则为__stdcall, 它是从右到左的,即函数中的最右边的参数最先入栈.例如,对于函数: void fu ...
- C语言中可变参数的用法
原文地址: http://blog.csdn.net/wooin/archive/2006/04/29/697106.aspx 我们在C语言编程中会遇到一些参数个数可变的函数,例如printf() ...
- C语言函数可变参数列表
C语言允许使用可变参数列表,我们常用的printf函数即为可变参数函数,C标准库提供了stdarg.h为我们提供了这方面支持:该头文件提供了一些类型和宏来支持可变参数列表,包括类型va_list,宏v ...
- C语言中可变参数的原理——printf()函数
函数原型: int printf(const char *format[,argument]...) 返 回 值: 成功则返回实际输出的字符数,失败返回-1. 函数说明: 使用过C语言的人所再熟悉不过 ...
- C语言的可变参数
可变参数给编程带来了很大的方便,在享受它带来的方便的同时,很有必要了解一下其实现方式,在了解编程语言的同时,也可以扩展编程的思路. 可变参数需要用到3个宏函数和一个类型,他们都定义在<stdar ...
随机推荐
- Navicat 12.1激活
去官网下载 https://www.navicat.com.cn/download/navicat-premium 然后下载这个破解包 第一个是整合了 navicat121_premium_cs_x6 ...
- python基础教程_查询价格
少儿编程和数学是有这一定联系的,若是将编程弄好了,数学成绩也就会有所提高,今天就为大家来介绍一下一个关于数学的相关编程,现在我们就来看看吧! 题目描述 编程实现以下功能:查询水果的单价.有4种水果,苹 ...
- c语言 判断字符串长度 实现
/* 首先明白答案的本质(该函数)是一个计数器该计数器用for循环来实现实现对一串字符串的计数字符串以空格开头 不计算空格 计算空格后的数字直到遇到\0结束.num计算器字符串不以空格结束 计算空格后 ...
- Kubernetes之动态Jenkins slave
一.前提 本次实践前,需已完成以下过程: 1.搭建好一个Kubernetes集群(本实践为单节点集群),网上参考较多,不赘述. 2.选取kubernetes集群外的一台服务器安装 NFS服务端,并在集 ...
- Golang 常用的第三方包.
Goland 下面这个license server 可用 http://idea.youbbs.org (2018-01-10 04:26:09) http://45.77.127.87:81(201 ...
- 在PHP中使用UUID扩展的函数
环境:CentOS Linux release 7.7.1908 (Core)PHP 7.3.11UUID Extention 1.0.4 感觉上PHP对UUID的支持似乎不是很上心,PECL中的UU ...
- 【leetcode-135,62,63 动态规划】分发糖果 ,不同路径
分发糖果 老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分. 你需要按照以下要求,帮助老师给这些孩子分发糖果: 每个孩子至少分配到 1 个糖果. 相邻的孩 ...
- 在 Target 中获取项目引用的所有依赖(dll/NuGet/Project)的路径
原文:在 Target 中获取项目引用的所有依赖(dll/NuGet/Project)的路径 在项目编译成 dll 之前,如何分析项目的所有依赖呢?可以在在项目的 Target 中去收集项目的依赖. ...
- 浏览器Notwork XHR被隐藏了
图片中红色区域内容被隐藏 解决方式,点击此处
- HDFS之安全模式
1.namenode启动的时候,首先将映像文件[fsimage]载入内存,并执行编辑日志[edits]中的各项操作. 2.一旦在内存中成功建立文件系统元数据的映射,则创建一个新的fsimage文件[这 ...