对于某些应用场景,某些函数的功能很相近,但是传入函数的参数个数不一样,使得我们必须使用不同的函数,比如2个数求平均,或者3个数求平均,甚至其他更多参数的情况;
今天使用可变长的函数来解决这个问题,需要使用标准库中包含的#include <stdio.h>和#include <stdarg.h>头文件,下面简述一下各个参数的意义。
1) va_list是C语言中的一个宏定义,用于定义一个指向变长参数列表的指针。必须通过宏va_start进行初始化,使指针指向传入的可变数据的列表,通过va_arg访问列表中的元素,和使用va_end释放列表占用空间。在函数中需要接收不定数量的参数时,可以使用va_list来处理这些参数。
2) va_start:初始化va_list的变量,它是一个宏定义,调用后va_list的变量指针指向传入的可变数据的列表的第一个元素。
va_start宏需要两个参数,分别是一个va_list类型的变量 和 可变参数(...)前的最后一个固定参数的标识符.
va_start宏没有返回值.
3) va_arg:依次获取列表中的元素,每次调用宏后都会自动变更va_list指向的地址。
va_arg宏需要两个参数,分别是一个va_list类型的变量 和 参数的数据类型.
va_arg宏的返回值是列表中的元素。
4) va_end:用于结束使用 va_start 和 va_arg 宏定义的可变参数列表,释放资源。
va_end宏需要一个参数,是一个va_list类型的变量。
va_end宏没有返回值.
看下面的例子(代码):
Case1:求多个数的平均值。
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"
#include "./usart/bsp_debug_usart.h"
#include <stdio.h>
#include <stdarg.h>
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
float average(int num, ...);
/* Private functions ---------------------------------------------------------*/
/**
* @brief main routine
* @param none
* @retval none
*/
int main(void)
{
/* USART initialization,baudrate 115200 8-N-1 , Remap fputc to usart1*/
Debug_USART_Config();
printf("Average of 255, 9, 16 = %f\r\n", average(3, 255,9,16));
while (1)
{}
}
/**
* @brief Average the variable amount of data
* @param num: Total number of data
* @param ...: variable data
* @retval none
*/
float average(int num, ...)
{
va_list valist;
float sum ;
va_start(valist, num);
for (int i = 0; i < num; i++)
{
sum += va_arg(valist, int);
}
va_end(valist);
return sum/num;
}
输出结果:Average of 255, 9, 16 = 93.333333
在这个case1中,average()函数中包括已固定的参数 num 和可变参数 ... ,在函数内部创建了va_list变量列表来表示可变参数,并用va_start进行初始化;使用va_arg获取列表中的元素,元素的表现方式为int数据类型,最后通过va_end释放资源。
case2: 将变长的输入变长的各种数据打印记录到文件中,此处暂记录到buffer中。
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"
#include "./usart/bsp_debug_usart.h"
#include <stdio.h>
#include <stdarg.h>
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
void my_convert(const char* format, ...);
/* Private functions ---------------------------------------------------------*/
/**
* @brief main routine
* @param none
* @retval none
*/
int main(void)
{
char argv0[] = "nice";
char argv1[] = "to meet";
char argv2[] = "you";
/* USART initialization,baudrate 115200 8-N-1 , Remap fputc to usart1*/
Debug_USART_Config();
my_convert("\r\n%s %s %s\r\n",argv0,argv1,argv2);
while (1)
{}
}
/**
* @brief Convert variable strings to one string.
* @param format: general a printf format including the escape character.
* @param ...: variable strings
* @retval none
*/
void my_convert(const char* format, ...)
{
char buffer[256];
va_list args;
va_start (args, format);
vsprintf (buffer,format, args);
va_end (args);
printf("%s",buffer);
}
输出结果:nice to meet you
在这个case2中,相比上面的case1,增加了vsprintf()函数,vsprintf函数通常用于把字符串格式化输出。它将数args按照字符串格式指定format进行格式化(包括%d%c%s%x等转义符),将输出果写入到字符串buffer中,并返回字符串长度,通过vsprintf()可以实现字符串的格式化输出,实现文件输出、参数输出和字符串输出等功能。
希望大家跟我交流哈~
遇事不决,可问春风,春风不语,即随本心。
诸君共勉!