stdarg.h头文件源代码分析

谈到C语言中可变参数函数的实现(参见C语言中可变参数函数实现原理),有一个头文件不得不谈,那就是stdarg.h

本文从minix源码中的stdarg.h头文件入手进行分析:

#ifndef _STDARG_H
#define _STDARG_H


#ifdef __GNUC__
/* The GNU C-compiler uses its own, but similar varargs mechanism. */

typedef char *va_list;

/* Amount of space required in an argument list for an arg of type TYPE.
 * TYPE may alternatively be an expression whose type is used.
 */

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

#if __GNUC__ < 2

#ifndef __sparc__
#define va_start(AP, LASTARG)                                           \
 (AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#else
#define va_start(AP, LASTARG)                                           \
 (__builtin_saveregs (),                                                \
  AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#endif

void va_end (va_list);          /* Defined in gnulib */
#define va_end(AP)

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

#else    /* __GNUC__ >= 2 */

#ifndef __sparc__
#define va_start(AP, LASTARG)                         \
 (AP = ((char *) __builtin_next_arg ()))
#else
#define va_start(AP, LASTARG)                    \
  (__builtin_saveregs (), AP = ((char *) __builtin_next_arg ()))
#endif

void va_end (va_list);        /* Defined in libgcc.a */
#define va_end(AP)

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

#endif    /* __GNUC__ >= 2 */

#else    /* not __GNUC__ */


typedef char *va_list;

#define __vasz(x)        ((sizeof(x)+sizeof(int)-1) & ~(sizeof(int) -1))

#define va_start(ap, parmN)    ((ap) = (va_list)&parmN + __vasz(parmN))
#define va_arg(ap, type)      \
  (*((type *)((va_list)((ap) = (void *)((va_list)(ap) + __vasz(type))) \
                            - __vasz(type))))
#define va_end(ap)


#endif /* __GNUC__ */

#endif /* _STDARG_H */

从代码中可以看到,里面编译器的版本以及相关的大量宏定义

第5行: #ifdef __GNUC__
作用是条件编译,__GNUC__为GCC中定义的宏。GCC的版本,为一个整型值。如果你需要知道自己的程序是否被GCC编译,可以简单的测试一下__GNUC__,假如你代码需要运行在GCC某个特定的版本下,那么你就要小心了,因为GCC的主要版本在增加,如果你想定义宏的方式直接实现控制,你可以写如下的代码(参见伯克利大学网站):

/* 测试 GCC > 3.2.0 ? */
#if __GNUC__ > 3 || \
    (__GNUC__ == 3 && (__GNUC_MINOR__ > 2 || \
                       (__GNUC_MINOR__ == 2 && \
                        __GNUC_PATCHLEVEL__ > 0))

 你还可以使用下面一个类似的方法:

#define GCC_VERSION (__GNUC__ * 10000 \
                     + __GNUC_MINOR__ * 100 \
                     + __GNUC_PATCHLEVEL__)
...
/*测试 GCC > 3.2.0 ?*/
#if GCC_VERSION > 30200

 第8行: 使用typedef进行了一个声明:typedef char *va_list;

 第14行:定义了用于编译器的内存对齐宏(参见C语言内存对齐详解(3)):

 

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

第17行:#if __GNUC__ < 2,进行GCC的版本判断,看当前版本是否大于2

第19行:#ifndef __sparc__ 可扩充处理器架构宏(以后再深入研究)

第20行:使得ap指向函数中的第一个无名参数的首地址的宏:

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

 第31行:

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

va_arg宏使得ap指向下一个参数,已经处理了内存对齐,其中参数的类型为TYPE

第48行:

void va_end (va_list);          /* Defined in gnulib */

  定义在gnulib中,va_end 与va_start成对使用.在有些代码中定义为:

#define va_end(ap)      ( ap = (va_list)0 )

  

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值