C语言中不定参数 ... 的语法以及函数封装

Intro

有一天看C代码看到某个方法有这样的定义:在函数形参列表处,有...的写法,就像Java中的不定参数那样。
如:

int	 printf(const char * __restrict, ...) __printflike(1, 2);
int	 scanf(const char * __restrict, ...) __scanflike(1, 2);

那么C语言中的不定参数特性,是怎样使用的呢,以及我们如何利用该特性,封装自己的函数?

语法测试

依赖库

需要用到 stdarg.h 中的三个函数:

#define va_start(ap, param) __builtin_va_start(ap, param)
#define va_end(ap) __builtin_va_end(ap)
#define va_arg(ap, type) __builtin_va_arg(ap, type)

新函数使用测试:遍历并打印不定参数中的值

主要是测试一下上面提到的三个库函数的使用。

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

// 声明列表的结束值
#define ARGUMENTS_END_VALUE -1

void printMultiArgs(int firstArgs, ...) {

 // 声明参数列表的变量
 va_list ap;
 
 // 初始化参数列表
 va_start(ap, firstArgs);
 printf("%d\n", firstArgs);
 
 int currValue;
 while ((currValue = va_arg(ap, int)) != ARGUMENTS_END_VALUE) {
 printf("%d\n", currValue);
 }

 // 结束参数列表
 va_end(ap);
}

int main(int argc, const char * argv[]) {
 printMultiArgs(1,2,3,4,5,6,7,8,9, ARGUMENTS_END_VALUE);
 return 0;
}

用两种方式封装函数:对多个int值求和

//
// main.c
// C不定参数
//
// Created by wuyujin1997 on 2023/1/23.
//

//#define va_start(ap, param) __builtin_va_start(ap, param)
//#define va_end(ap) __builtin_va_end(ap)
//#define va_arg(ap, type) __builtin_va_arg(ap, type)

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

// 声明列表的结束值
#define ARGUMENTS_END_VALUE -1

void printMultiArgs(int firstArgs, ...) {

 // 声明参数列表的变量
 va_list ap;
 // 初始化参数列表
 va_start(ap, firstArgs);
 printf("%d\n", firstArgs);
 
 int currValue;
 while ((currValue = va_arg(ap, int)) != ARGUMENTS_END_VALUE) {
 printf("%d\n", currValue);
 }

 // 结束参数列表
 va_end(ap);
}


/// 对多个int变量求和(需要提前约定好参数结束的标志值 ARGUMENTS_END_VALUE)
/// - Parameter firstArgs: <#firstArgs description#>
int sum1(int firstArgs, ...) {
 int result = 0;
 
 va_list ap;
 va_start(ap, firstArgs);
 result+= firstArgs; // 手动处理第一个参数
 int currValue;
 while ((currValue = va_arg(ap, int)) != ARGUMENTS_END_VALUE) {
 result += currValue;
 }
 va_end(ap);
 
 return result;
}


/// 对多个int变量求和(需要主动本方法:不定参数的个数是多少)
/// - Parameters:
/// - count: 不定参数的个数
/// - firstArgs: 第一个参数,显式的形参
int sum2(int count, int firstArgs, ...) {
 int result = 0;
 
 va_list ap;
 va_start(ap, firstArgs);
 result += firstArgs;
 for (int i = 1; i < count; i++) {
 int currValue = va_arg(ap, int);
// printf("%d %d\n", i, currValue);
 result += currValue;
 }
 va_end(ap);
 
 return result;
}

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

 printMultiArgs(1,2,3,4,5,6,7,8,9, ARGUMENTS_END_VALUE);
 printf("sum1 %d\n", sum1(1,2,3,4,5,6,7,8,9, ARGUMENTS_END_VALUE));
 int LENGTH = 9;
 printf("sum2 %d\n", sum2(LENGTH, 1,2,3,4,5,6,7,8,9, ARGUMENTS_END_VALUE));

 return 0;
}

执行结果:

总结

  • 需要引入头文件 #include <stdarg.h>
  • 一个新类型,三个新函数
    • 类型 va_list
    • 函数,其中 ap 为 va_list 类型的变量。
      • va_start(ap, param) param为不定参数列表的第一个参数。
      • va_arg(ap, type) 不定参数中变量的类型吗,如int, short, long 等。
      • va_end(ap)
  • 如何确定 va_arg 的size/有多少个元素? 没有原生的属性/变量可以告诉我们。
    • 约定一个值作为 end_value ,而且要保证:这个值不会出现在传入的多个参数值中。
    • 在咱自己封装的函数中,新增一个参数用于告知被调函数内部:本次不定参数的size是多少。
  • 注意不定参数的类型匹配。

总结 

作者:锦天原文地址:https://blog.csdn.net/wuyujin1997/article/details/128752337

%s 个评论

要回复文章请先登录注册