C可变参数实现原理

18 篇文章 0 订阅
1 篇文章 0 订阅

在C程序设计语言中,使用printf函数进行标准输出。

int printf ( const char * format, ... );

printf函数申明中"..."代表可变参数。

printf ("floats: %4.2f %+.0e %E \n", 3.1416, 3.1416, 3.1416);
printf ("Width trick: %*d \n", 5, 10);

那么,如何实现可变参数?

近日,在读Linux0.12源代码的过程中,我看到了一个实现。下面,我给出一个demo程序。

#include <iostream>
using namespace std;


typedef char *va_list;

#define __va_rounded_size(TYPE)  \
  (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))

#define va_start(AP, LASTARG) 						\
 (AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))


#define va_end(AP)  

#define va_arg(AP, TYPE)						\
 (AP += __va_rounded_size (TYPE),					\
  *((TYPE *) (AP - __va_rounded_size (TYPE))))


void print_args(int args, ...)
{
    va_list ap;
    //在访问任何未命名的参数之前,必须用va_start宏初始化ap一次
    va_start(ap,args);
    printf("%d\n",args);
    printf("%d\n",va_arg(ap,int));
    printf("%s",va_arg(ap,char *));
//  va_end(ap);
}


int main(void)
{
    int arg = 2;
    int args1 = 1;
    char *args2  = "abcdefg";
    print_args(2,args1,args2);
    return 0;
}

不妨在print_args程序中设置一个断点

首先,查看一下args参数的内存地址:

+		&args	0x0028f71c	int *

现在,我们查看0x0028f71c处的内存:

0x0028F71C  02 00 00 00  ....
0x0028F720  01 00 00 00  ....
0x0028F724  08 58 cd 00  .X?.

显然, 0x0028f71c处的4个字节为0x00000002,即main函数中的arg参数;

0x0028f720处的4个字节为0x00000001,即main函数中的args1参数;

而0x0028f724处的4个字节内容为0x00cd5808,这是一个内存地址;

0x00CD5808  61 62 63 64  abcd
0x00CD580C  65 66 67 00  efg.

继续查看0x00cd5808处的内存,可以看出正是"abcdefg\0"。


有了上面的基础,我们应当可以理解va_start, va_end和va_arg宏了。实际上,就是对地址的操作,以及强制类型转换。printf函数也是利用上面3个宏实现可变参数功能的。




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值