使用可变参数列表,可以让函数在不同场合接收不同数量的参数传入,printf函数的格式化输出,就是一个典型的例子。
printf("<格式化字符串>", <参量表>); //printf函数的使用
int printf(const char *format, ...); //printf函数的原型
函数对可变参数的访问
可变参数列表通过定义与starg.h的宏来实现。构造这种函数,利用一个类型va_list 和 三个宏va_start、va_arg、va_end来实现对可变参数的访问。下面的例程实现对传入数值求平均值,并返回平均值。
#include <stdio.h>
#include <stdarg.h>
/*
**求均值函数
**输入:n_values 指定数量 <参数表>
**输出:求出的平均值
*/
float average( int n_values, ... ) // ...表示可变参数列表,此时这些参数的类型还没有确定
{
va_list var_arg; //用于遍历列表中的参数
int count;
float sum = 0;
va_start( var_arg, n_values );
for( count=0; count < n_values; count +=1 )
{
sum += va_arg( var_arg, int ); //为每下个可变参数指定 int 类型
}
va_end( var_arg );
return sum/n_values;
}
void main(void)
{
float temp = 0;
temp = average( 3, 6, 3, 3 ); //3个数值分别是 6、3、3
printf("%f\n",temp);
}
实现
分析
va_start根据第二个参数n_values(函数average的最后一个有名参数),将va_list类型变量var_arg指定列表中第1个参数
va_start( var_arg, n_values );
va_arg根据第二个参数int来指定va_list类型变量var_arg在列表中的下一个参数
va_arg( var_arg, int );
va_end表示访问完毕
va_end( var_arg );
但是根据上面的结果,有两点不足:
1.使用average函数需要指定传入参数的数量,不方便
2.没有办法判断每一个可变参数的类型
构造printf()--串口输出
想想在printf函数中,通过格式化输出(匹配格式号),我们不仅不用指定参数的数量,还不用指定参数的类型。
这里使用vsprintf函数结合上面的可变列表,来构造一个串口输出的实例
int vsprintf(char *str, const char *format, va_list arg); //vsprintf函数原型
//串口2,printf 函数
//确保一次发送数据不超过USART2_MAX_SEND_LEN字节
void u2_printf(char* fmt,...)
{
u8 *TXStr;
va_list ap;
va_start(ap,fmt);
vsprintf((char*)USART2_TX_BUF,fmt,ap);
va_end(ap);
TXStr = (u8*)USART2_TX_BUF;
while(*TXStr != 0) //当前字符不为空
{
USART_SendData(USART2, *TXStr); //向串口1发送数据
while(USART_GetFlagStatus(USART2,USART_FLAG_TC)!=SET);//等待串口2发送结束 TX自动置0
TXStr++;
}
}
同样,先声明va_list类型变量ap,va_start宏将ap指向可变列表第一个参数;vsprintf将可变列表格式化输出到内存,fmt代表格式化匹配规则;最后va_end结束。然后就可以通过串口底层,将USART2_TX_BUF中的数据发送到连接串口的另一端设备了。