1. 程式人生 > 其它 >c - variadic function - 引數【個數】可變函式

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.intprintf(constchar*format, ...);

Seevariadic argumentsfor 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 undergoesinteger promotion

(see below), and each argument of typefloatis implicitly converted to the typedouble

每個 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);

Theva_copymacro copiessrctodest.

va_endshould be called ondestbefore the function returns or any subsequent re-initialization ofdest(via calls tova_startorva_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));
}