• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

va_list实现不定参数C函数

原作者: [db:作者] 来自: [db:来源] 收藏 邀请
void vltest(int i, float k, ...){
    va_list vl; //定义va_list变量vl,该变量是指向参数的指针
    va_start(vl, k); // 参数一:va_list变量vl;参数二:va_list变量vl中最后一个固定参数
    int j = va_arg(vl, int); // 参数一:va_list变量vl;参数二:可变参数的类型,返回值j即可变参数
    double m = va_arg(vl, double); // 同上
    unsigned long n = va_arg(vl, unsigned long); // 同上
    va_end(vl); // 结束可变参数的获取
    printf("i = %d, k = %.f, j = %d, m = %lf, n = %lu\r\n", i,k, j, m, n);
}

上述方法不能智能识别不同参数的个数和类型。

如果想实现智能识别可变参数,比如printf,需要在自己的程序中作特殊处理,示例如下:

#include <stdarg.h>
 2 
 3 void my_printf(const char* fmt, ... )
 4 {
 5     va_list ap;
 6     va_start(ap,fmt); /* 用最后一个具有参数的类型的参数去初始化ap */
 7     for (;*fmt;++fmt)
 8     {
 9         /* 如果不是控制字符 */
10         if (*fmt!='%')
11         {
12             putchar(*fmt); /* 直接输出 */
13             continue;
14         }
15         /* 如果是控制字符,查看下一字符 */
16         ++fmt;
17         if ('\0'==*fmt) /* 如果是结束符 */
18         {
19             assert(0);  /* 这是一个错误 */
20             break;
21         }
22         switch (*fmt)
23         {
24         case '%': /* 连续2个'%'输出1个'%' */
25             putchar('%');
26             break;
27         case 'd': /* 按照int输出 */
28             {
29                 /* 下一个参数是int,取出 */
30                 int i = va_arg(ap,int);
31                 printf("%d",i);
32             }
33             break;
34         case 'c': /* 按照字符输出 */
35             {
36                 /** 但是,下一个参数是char吗*/
37                 /*  可以这样取出吗? */
38                 char c = va_arg(ap,char);
39                 printf("%c",c);
40             }
41             break;
43         }
44     }
45     va_end(ap);  /* 释放ap—— 必须! 见相关链接*/
46 }

在C语言中,调用一个不带原型声明的函数时:

调用者会对每个参数执行“默认实际参数提升(default argument promotions)”。

同时,对可变长参数列表超出最后一个有类型声明的形式参数之后的每一个实际参数,也将执行上述提升工作。
提升工作如下:
——float类型的实际参数将提升到double
——char、short和相应的signed、unsigned类型的实际参数提升到int
——如果int不能存储原值,则提升到unsigned int

然后,调用者将提升后的参数传递给被调用者。

因此,my_printf是绝对无法接收到上述类型的实际参数的。

上面的代码的38与39行,应该改为:

int c = va_arg(ap,int);
printf("%c",c);

同理, 如果需要使用short和float, 也应该这样:

short s = (short)va_arg(ap,int);
float f = (float)va_arg(ap,double);

 

总之,va_arg(ap,type)中的type绝对不能为以下类型:
——char、signed char、unsigned char
——short、unsigned short
——signed shortshort int、signed short int、unsigned short int
——float

注:部分编译器,如笔者所测试的xCode4.3,输入上述错误类型后有警告提示。

 

参考:

http://jazka.blog.51cto.com/809003/232331

http://www.cplusplus.com/reference/clibrary/cstdarg/va_start/

可变长参数列表误区与陷阱——va_arg不可接受的类型

可变长参数列表误区与陷阱——va_end是必须的吗?


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
C#处理大量数据的技巧发布时间:2022-07-14
下一篇:
C#学习(六)之LINQ发布时间:2022-07-14
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap