c语言——可变参数

本文详细介绍了C语言中的可变参数概念,包括如何使用va_list、va_start、va_arg和va_end等宏来处理可变参数。同时,还提供了一个自定义的myprintf函数示例,展示了如何实现类似printf的功能。

C语言——可变参数


宗旨:技术的学习是有限的,分享的精神是无限的。


1、目前为止,见过比较熟悉的可变参数的函数就是printf()函数

[cpp]  view plain  copy
 print ?
  1. int printf(const char *format, …);<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>  

2、可变参数宏

[cpp]  view plain  copy
 print ?
  1. void va_start(va_list arg_ptr, prev_param);  
  2. type va_arg(va_list arg_ptr, type);  
  3. void va_end(va_list arg_ptr);  

va_list:用来保存宏va_start、va_arg和va_end所需信息的一种类型。为了访问变长参数列表中的参数,必须声明va_list类型的一个对象      定义: typedef char *  va_list;
va_start:访问变长参数列表中的参数之前使用的宏,它初始化用va_list声明的对象,初始化结果供宏va_arg和va_end使用;
va_arg: 展开成一个表达式的宏,该表达式具有变长参数列表中下一个参数的值和类型。每次调用va_arg都会修改用va_list声明的对象,从而使该对象指向参数列表中的下一个参数;
va_end:该宏使程序能够从变长参数列表用宏va_start引用的函数中正常返回。

C语言内存管理中,我们提到函数的参数存放在栈中。通过反汇编可知,可变参数是从右向左依次压栈的,所以第一个参数靠近栈顶,最后一个参数靠近栈底。这些参数在内存中是连续存放的,每个参数都4字节对齐。

 

3stdarg.h的一种实现

[cpp]  view plain  copy
 print ?
  1. /* stdarg.h standard header */  
  2. #ifndef _STDARG  
  3. #define _STDARG  
  4. /* type definitions */  
  5. typedef char *va_list;  
  6. /* macros */  
  7. #define va_arg(ap, T) \  
  8.         (* (T *)(((ap) += _Bnd(T, 3U)) - _Bnd(T, 3U)))  
  9. #define va_end(ap) (void)0  
  10. #define va_start(ap, A) \  
  11.         (void)((ap) = (char *)&(A) + _Bnd(A, 3U))  
  12. #define _Bnd(X, bnd) (sizeof (X) + (bnd) & ~(bnd))  
  13. #endif /*<span style="font-family: Arial, Helvetica, sans-serif;">_STDARG</span> */  

这个头文件中的内部宏定义将类型或变量的长度对齐到字节的整数倍,例如_Bnd(char, 3U)的值是4_Bnd(int, 3U)也是4

 

4、可变参数函数实现思路

1)首先在函数里定义一个va_list型的变量,这里是arg_ptr,这个变 量是指向参数的指针。
2)然后用va_start宏初始化变量arg_ptr,这个宏的第二个参数是第 一个可变参数的前一个参数,是一个固定的参数。

3)然后用va_arg返回可变的参数,并赋值给整数j. va_arg的第二个参数是你要返回的参数的类型,这里是int型。
4)最后用va_end宏结束可变参数的获取.然后你就可以在函数里使 用第二个参数了.如果函数有多个可变参数的,依次调用va_arg 取各个参数。

 

5myprintf函数实现

[cpp]  view plain  copy
 print ?
  1. #include <stdio.h>  
  2. #include <stdarg.h>  
  3.   
  4. void myprintf(const char *format, ...)  
  5. {  
  6.   va_list ap;  
  7.   char c;  
  8.   
  9.   va_start(ap, format);  
  10.   while(c = *format++)  
  11.   {  
  12.     switch(c)  
  13.     {  
  14.     case 'c':  
  15.     {  
  16.       char ch = va_arg(ap, int);  
  17.       putchar(ch);  
  18.       break;  
  19.     }  
  20.   
  21.     case 's':  
  22.     {  
  23.       char *p = va_arg(ap, char *);  
  24.       fputs(p, stdout);  
  25.       break;  
  26.     }  
  27.   
  28.     default:  
  29.       putchar(c);  
  30.     }  
  31.   }  
  32.   va_end(ap);  
  33. }  
  34.   
  35. int main(void)  
  36. {  
  37.   myprintf("c\ts\n"'1'"hello");  
  38.   
  39.   return 0;  
  40. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值