参考资料:
1、MSDN, 查询 ... ellipsis 关键字;
2、http://www.cppblog.com/ownwaterloo/archive/2009/04/21/unacceptable_type_in_va_arg.html;
3、http://blog.csdn.net/zxianrong/article/details/3706405。
运行环境:
1、Windows XP Home Ed SP3;
2、Visual C++ 6.0 Enterprise Edition。
/*
Date: 2011-08-06
Author: garyHost;
Description: 利用stdarg.h来实现可变参数列表;
Remarks:
*/
#include <stdio.h>
#include <stdarg.h> //可变参数列表所需要的头文件;
//**函数功能:获得分数的平均值;
/*参数列表中【...】表示参数数目不定,而且类型也不定,所以在执行函数之前会进行一系列按照规则的数据转换,即:float -> double; char, short, 枚举类型等 -> int。第一个参数是必要的,可以这样理解所有的参数都保存在一个连续的存储空间中,如同数组,必须由一个参数来告诉初始化程序这个参数列表从什么地方开始。*/
float average(float firstScore, ...)
{
int count = 0;
float sum = 0.0F; //用于记录总分;
float i = firstScore;
va_list marker; //va_list中保存的是参数列表va_arg中所需要的相关信息;在VC的定义中是一个char * 类型,字符指针变量;
va_start(marker, firstScore); //初始化参数列表,将marker指向firstScore后面那个参数(即:第二个参数);
while( i > 0 ) //循环的终止条件,这里假设分数不能为负数;
{
sum += i;
count++;
i = (float) va_arg( marker, double); /*完成两个功能:1、获取当前这个参数值,而参数的类型由给出的数据类型确定;
2、将参数列表的指针移动到下一个参数的位置。
这里需要注意的是由于上面提及的函数参数类型的转换,本函数中输入的float参数都
被自动转化成了double类型,所以这里数据类型需要设置为double,而非float。如果
设置为float,那么如果float和double所占的内存空间不相同则可能导致数据的读取错误。*/
}
va_end( marker ); //从va_end的实现来看是将marker指针指向NULL,由此可以推断参数列表所占内存空间是由编译器自动释放的;
return(sum ? (sum / count) : 0);
}
int main(void)
{
float avg = average(95.5F, 96.0F, 100.0F, 80.0F, 85.5F, -1.0F); //最后的-1.0F是休止符;
printf("avg = %g\n\n", avg);
/*以下代码是用于模拟函数参数类型默认转换的情况,针对以上为什么va_arg(marker, float)是错误的问题;主要原因是:float和double在内存中所占字 节数不相同造成的问题,比如,在我的计算机环境下(windows xp home ed sp3,vc 6.0 enterprise)通过sizeof(float) = 4, sizeof(double) = 8,即:float占4个字节,double占8个字节;那么如果使用了va_arg(marker, float)由于va_arg是由宏来定义的,va_arg(marker, float) <=> ( *(float *)((marker += _INTSIZEOF(float)) - _INTSIZEOF(float)))由这个语句可以看出由于指针类型的转化,那么本来连续8个字节都用来保存一个分数,但是现在只使用其中4个字节的内容,当然数据就会出现丢失,从而导致程序运行结果出乎意料。以下是一个实质相同的模拟过程:*/
double d = 21.7;
float f = *((float *)(&d)); //指针类型转化 double * -> float *;
printf("d(double) = %g\n\n", d);
printf("f(float) = %g\n\n", f);
f = (float)d;
printf("f = (float)d = %g\n\n", f); //强制转化不同,因为不涉及到寻址长度,而是数据值的拷贝,只有溢出的风险。
return (0);
}
/*
在我机器上的运行结果:
avg = 91.4
d(double) = 21.7
f(float) = 4.17233e-008
f = (float)d = 21.7
Press any key to continue
*/