[C语言]利用stdarg.h来实现可变参数列表

 参考资料:

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
*/


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值