zoukankan      html  css  js  c++  java
  • stdarg.h头文件源代码分析

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

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

     1 #ifndef _STDARG_H
     2 #define _STDARG_H
     3 
     4 
     5 #ifdef __GNUC__
     6 /* The GNU C-compiler uses its own, but similar varargs mechanism. */
     7 
     8 typedef char *va_list;
     9 
    10 /* Amount of space required in an argument list for an arg of type TYPE.
    11  * TYPE may alternatively be an expression whose type is used.
    12  */
    13 
    14 #define __va_rounded_size(TYPE)  \
    15   (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
    16 
    17 #if __GNUC__ < 2
    18 
    19 #ifndef __sparc__
    20 #define va_start(AP, LASTARG)                                           \
    21  (AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
    22 #else
    23 #define va_start(AP, LASTARG)                                           \
    24  (__builtin_saveregs (),                                                \
    25   AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
    26 #endif
    27 
    28 void va_end (va_list);          /* Defined in gnulib */
    29 #define va_end(AP)
    30 
    31 #define va_arg(AP, TYPE)                                                \
    32  (AP += __va_rounded_size (TYPE),                                       \
    33   *((TYPE *) (AP - __va_rounded_size (TYPE))))
    34 
    35 #else    /* __GNUC__ >= 2 */
    36 
    37 #ifndef __sparc__
    38 #define va_start(AP, LASTARG)                         \
    39  (AP = ((char *) __builtin_next_arg ()))
    40 #else
    41 #define va_start(AP, LASTARG)                    \
    42   (__builtin_saveregs (), AP = ((char *) __builtin_next_arg ()))
    43 #endif
    44 
    45 void va_end (va_list);        /* Defined in libgcc.a */
    46 #define va_end(AP)
    47 
    48 #define va_arg(AP, TYPE)                        \
    49  (AP = ((char *) (AP)) += __va_rounded_size (TYPE),            \
    50   *((TYPE *) ((char *) (AP) - __va_rounded_size (TYPE))))
    51 
    52 #endif    /* __GNUC__ >= 2 */
    53 
    54 #else    /* not __GNUC__ */
    55 
    56 
    57 typedef char *va_list;
    58 
    59 #define __vasz(x)        ((sizeof(x)+sizeof(int)-1) & ~(sizeof(int) -1))
    60 
    61 #define va_start(ap, parmN)    ((ap) = (va_list)&parmN + __vasz(parmN))
    62 #define va_arg(ap, type)      \
    63   (*((type *)((va_list)((ap) = (void *)((va_list)(ap) + __vasz(type))) \
    64                             - __vasz(type))))
    65 #define va_end(ap)
    66 
    67 
    68 #endif /* __GNUC__ */
    69 
    70 #endif /* _STDARG_H */
    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 )
  • 相关阅读:
    Weblogic 12c 集群部署和session复制
    Weblogic 12c 集群环境搭建
    Programming In Scala笔记-第十九章、类型参数,协变逆变,上界下界
    这是最好的时光,这是最坏的时光 SNAPSHOT
    这是最好的时光 这是最坏的时光 v0.1.1.1
    鹅厂欧阳大神给年轻人的一些分享
    谈到电影,我们收获了什么
    那些被电影搞的日子
    Programming In Scala笔记-第十五章、Case Classes和模式匹配
    [CSharp]传一个包含多个属性的对象,只改变其中个别属性值的方法
  • 原文地址:https://www.cnblogs.com/cpoint/p/3374994.html
Copyright © 2011-2022 走看看