zoukankan      html  css  js  c++  java
  • 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 ", 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
    ", sample_stddev(4, 25.0, 25.0, 25.0, 25.0));
    
    	return 0;
    }
    
    
    

     这个是va_copy的函数用法,

     
  • 相关阅读:
    5.共享文件夹
    4.CentOS安装
    JS 递归
    Gulp 笔记
    Js call apply bind区别
    Js new 过程解析
    Js 原型和原型链
    JS blur和click 顺序冲突
    重新认识button disabled属性
    英语笔记3
  • 原文地址:https://www.cnblogs.com/CodeWorkerLiMing/p/11871451.html
Copyright © 2011-2022 走看看