//
//  main.c
//  test
//
//  Created by cbd on 01/01/2017.
//  Copyright © 2017 cbd. All rights reserved.
//

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>


int64_t sum(int c_num, ...);

int main(int argc, const char * argv[]) {

    int64_t result = sum(3, 1,2,3);

    //int	 printf(const char * __restrict, ...) __printflike(1, 2);
    printf("sum: %lld\n", result);

    return EXIT_SUCCESS;
}


/**
 任意多个数相加求和

 @param c_num 加数个数
 @param ...   加数

 @return 和
 */
int64_t sum(int c_num, ...) {
    va_list addend_list;
    int64_t sum = 0;

    va_start(addend_list, c_num);

    for (int i = 0; i< c_num; i++) {
        sum += va_arg(addend_list, int);
    }

    va_end(addend_list);

    return sum;
}

小结

va_list/va_start/va_arg/va_end 配合使用。

va_list 用来声明一个变量,此处即addend_list。 该变量其实是个指针,由va_start来初始化,第一个参数为该变量,第二个参数为函数声明中 ... 前面的一个变量。 也就是所函数原型中至少有一个类型和名称都确定的参数。

依次调用 va_arg 来获取 可变参数中的具体参数。va_arg 要求明确知道总共有几个参数和每个参数的类型。但参数类型只会是int或double,此时会发生缺省参数类型提升。

当调用一个没有声明原型的函数时,会发生默认参数提升。

这里 ... 也其中一种情况,因为编译器并不知道入参到底是什么类型,和没有函数声明同样对待。

可变参数列表最典型的应用就是 printf("%d\n",129);"%d\n" 就是第一个确定的参数, %d 用来标示后面的参数要用什么类型来解释。 所以该类型必须是明确的准确的,也就是『类型不安全』的,因为prinf不可能再根据其他信息猜测更多。