宏和函数的可变参数问题

本文介绍了宏和函数处理可变参数的方法。在宏方面,展示了如何使用`__VA_ARGS__`简化调试宏。在函数方面,详细阐述了处理可变参数的五个步骤,包括`va_list`、`va_start`、`va_copy`、`va_arg`和`va_end`的使用。同时,强调了在函数原型和定义中使用可变参数的规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

宏的可变参数(variadic macros)

#include <stdarg.h>

#define  yourmacro(...)     aa(__VA_ARGS__);


在调试程序的时候,通常会添加
#ifdef _DEBUG
//Debug_printf(参数);
#endif

在每一处调试的地方都需要添加这种宏会很麻烦,为了使系统更加简单,此时可以考虑使用可变参数的宏对其进行简化。如下所示:

在调试程序中,可以使用如下:
#ifdef _DEBUG
#define DEBUG(...)    Debug_print(__VA_ARGS__);
#else
#define DEBUG(...)
#endif

此时在需要调试的地方直接添加如下语句即可。
DEBUG(参数);



函数的可变参数使用的步骤:
     1. 在函数的原型中采用“...";    
     2. 函数的定义中采用va_list类型的变量;
     3. 利用宏初始化参数列表va_start(va_list ap, parmN);
     4. 利用宏访问参数列表va_arg(va_list ap, type);
     5. 利用宏清除va_end(va_list ap)。

使用的数据有如下几类:
     1. va_list: 用于存放可变参数的信息
     2. void va_start(va_list ap, parmN);  
          //这个宏用在va_arg()以及va_end()之前用于初始化va_list ap;parmN是可变参数函数的参数表中“..."前的第一个参数。
     3. void va_copy(va_list dest, va_list src);    
          //this macro initializes dest as a copy of the current state of src. (C99).由于va_arg对参数表的访问是单向的,不能返回。所以当需要返回的时候,此时可以采用复制va_list的方法。
     4. type va_arg(va_list ap, type);
          //这宏用于获取va_list中的参数。type是这个参数的类型。每次调用后,都指向了va_list  ap中下一个参数的值。
     5. void va_end(va_list ap);
          //这个宏关闭了这个过程,并使得ap不能再被使用了。

这些数据在stdargs.h中有定义,以_builtin开头的参数是编译器可以识别的数据或函数。

//stdargs.h-------va_list/va_start/va_end/va_arg/va_copy的定义。

typedef __builtin_va_list __gnuc_va_list;

#ifndef __va_list__
typedef __gnuc_va_list va_list;
#endif /* not __va_list__ */

#ifdef _STDARG_H

#define va_start(v,l)    __builtin_va_start(v,l)
#define va_end(v)    __builtin_va_end(v)
#define va_arg(v,l)    __builtin_va_arg(v,l)
#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L || defined(__GXX_EXPERIMENTAL_CXX0X__)
#define va_copy(d,s)    __builtin_va_copy(d,s)
#endif
#define __va_copy(d,s)    __builtin_va_copy(d,s)

函数的原型:
     1. 用“..."表示可变参数;
     2. “..."必须位于参数表的最后;
     3. "..."前至少有一个参数,最靠近“..."的参数称为parmN.
函数的原型举例:
    void f1(int n, ...);
    int f2(const char *s, int k, ...);
    char f3(char c1, ..., char c2);  //  invalid
    double f3(...);                      // invalid

函数的实现举例定义
int
__printf (const char *format, ...)
{
      va_list arg;
      int done;
    
      va_start (arg, format);    //  两个参数; 一个为va_start;另一个为 parmN;
      done = vfprintf (stdout, format, arg);
      va_end (arg);
    
      return done;
}
 
举例2
#include <stdio.h>
#include <stdarg.h>

double sum(int, ...);

int main(void)
{
     double s,t;
     s = sum(3, 1.1, 2.5, 13.3);
    
     return 0;
}

double sum(int lim, ...)
{
     va_list ap;
     double tot = 0;
     int i;

     va_start(ap, lim);
     for(i=0; i < lim, i++)
          tot += va_arg(ap,double);
     va_end(ap);
}






















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值