c - variadic function - 参数【个数】可变函数

 

参考

https://en.cppreference.com/w/c/variadic

https://en.cppreference.com/w/c/language/variadic

 

参数可变函数

The declaration of a variadic function uses an ellipsis as the last parameter,

e.g. int printf(const char* format, ...);

See variadic arguments for additional detail on the syntax and automatic argument conversions.

 

参数可变函数声明时,最后一个 参数 使用 三个点好  来表示。

示例: int printf(const char * format, ... ); 

https://en.cppreference.com/w/c/language/variadic 里面介绍 可变参数和 参数类型转换。

 

参数类型转换

1、对于没有 函数原型  的函数的调用  

2、对于 参数可变函数的调用(中的 可变参数部分),

这两种情况下,传递进入的参数都会进行 隐式转换

见 https://en.cppreference.com/w/c/language/conversion#Default_argument_promotions

 

Each argument of integer type undergoes integer promotion (see below), and each argument of type float is implicitly converted to the type double

 

每个 integer 类型的参数都  转换为int  ; 每个 浮点 参数 都转换为 double 类型。

int add_nums(int count, ...);
int sum = add_nums(2, 'c', true); // add_nums is called with three ints: (2, 99, 1)

 

处理可变参数

 macro 下面这几个是 宏定义

va_start  

va_arg 

va_end 

va_copy  c99 中引入

type  下面这个是 类型定义

va_list

 

使用示例

#include <stdio.h>
#include <stdarg.h>
 
void simple_printf(const char* fmt, ...)
{
    va_list args;           // va_list 定义一个 变量,用于存放 信息
    // va_start 宏-第一个参数是 va_list 定义的变量,第二个参数是 函数 可变参数前面的一个参数。
    // va_start 和 va_end 一一对应
    va_start(args, fmt);   
 
    while (*fmt != '\0') {
        if (*fmt == 'd') {
            int i = va_arg(args, int); // va_arg 第一个是 va_list 定义的变量,第二个是类型
            printf("%d\n", i);
        } else if (*fmt == 'c') {
            // A 'char' variable will be promoted to 'int'
            // A character literal in C is already 'int' by itself
            int c = va_arg(args, int);
            printf("%c\n", c);
        } else if (*fmt == 'f') {
            double d = va_arg(args, double);
            printf("%f\n", d);
        }
        ++fmt;
    }
 
    va_end(args);  // va_end 宏只需要一个参数
}
 
int main(void)
{
    simple_printf("dcff", 3, 'a', 1.999, 42.5); 
}

  

va_copy 示例 - 求标准差

void va_copy(va_list dest, va_list src);   

The va_copy macro copies src to dest.

va_end should be called on dest before the function returns or any subsequent re-initialization of dest (via calls to va_start or va_copy).

 

#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, 27.3, 26.9, 25.7));
}

  

 

posted @ 2022-01-16 20:14  张志伟122  阅读(65)  评论(0编辑  收藏  举报