码迷,mamicode.com
首页 > 其他好文 > 详细

可变参数的函数(variadic function)的陷阱

时间:2015-04-15 13:26:40      阅读:167      评论:0      收藏:0      [点我收藏+]

标签:

1,介绍variadic function

可变参数的函数就是参数数量可以改变的函数。例如printf();

int printf(const char *format, ...);
printf("%d%s\n",i,s);

C语言之所以可以支持可变参数函数,一个重要的原因是C调用规范中规定C语言函数调用时,参数是从右向左压入栈的;这样一个函数实现的时候,就无需关心调用他的函数会传递几个参数过来,而只要关心自己用到几个;
例子:

#include<stdarg.h>

void print_int(int args,...)
{
 va_list ap;              //va_list 用来保存传给函数的其他参数。
 va_start(ap,args);  //说明可变参数从哪里开始
 for(int i=0;i<args;i++){
  printf("argument: %i\n",va_arg(ap,int));
 }
 va_end(ap);
}
这里用到一系列宏来帮助完成可变参数函数参数:va_start、va_arg和va_end;

在ANSI C标准下,这些宏定义在stdarg.h中。三个宏的原型如下:


void va_start(va_list ap, last);//取第一个可变参数(如上述printf中的i)的指针给ap,last是函数声明中的最后一个固定参数(比如printf函数原型中的*fromat);

type va_arg(va_list ap, type);//返回当前ap指向的可变参数的值,然后ap指向下一个可变参数;type表示当前可变参数的类型(支持的类型位int和double);

void va_end(va_list ap);//将ap置为NULL

2,陷阱

贴出一个计算一个账单的程序(来自嗨翻C语言),ABCD分别是四种酒水的名字。但是每位客人可能只点一种,也可能点某几种酒水。所以参数不定。

enum drink{A,B,C,D};//定义枚举类型
double price(enum drink d){ //每种酒水的价钱
 switch(d){
  case A:
    return 6.79;
  case B:
    return 5.31;
  case C:
    return 4.82;
  case D:
    return 5.89;
  }
 return 0;
}

double total(int args,...)//核心程序,算出总的价钱。
{
 double total=0;
 va_list ap;
 va_start(ap,args);
 int i;
 for(i=0;i<args;i++){
  enum drink d=va_arg(ap,enum drink);//问题出在这个enum drink 上,将其改为int就出结果了,当然类型不匹配也会出现警告,但没办法,这就是缺陷所在了。
  total+=price(d);
 }
 va_end(ap);
 return total;

问题来了:编译时,出现warning: `drink‘ is promoted to(提升为) `int‘ when passed through `...‘(so you should pass `int‘ not `drink‘ to `va_arg‘)
if this code is reached, the program will abort.

而且这个程序打印不出total的价格,运行崩溃。

书中的解答:

va_arg宏的第2个参数不能被指定为char、short或者float类型。《C和C++经典著作:C陷阱与缺陷》在可变参数函数传递时,因为char和short类型的参数会被提升为int类型,而float类型的参数会被提升为double类型 。

可变参数的函数(variadic function)的陷阱

标签:

原文地址:http://www.cnblogs.com/ypsun/p/4428121.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!