`

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 )

  

分享到:
评论

相关推荐

    《unix网络编程》源代码

    ### 《Unix网络编程》源代码分析 #### 一、简述 《Unix网络编程》是一本详尽介绍Unix环境下网络编程技术的经典书籍,书中包含了大量实用的代码示例,帮助读者深入理解网络编程的核心原理与实践技巧。本文将重点...

    C标准库完整的源代码

    7. 其他功能:还有如`assert.h`头文件中的`assert`宏用于调试,`stdarg.h`支持可变参数列表,`setjmp.h`和`longjmp`用于非局部跳转等。 通过研究C标准库的源代码,你可以深入了解函数如何实现、错误处理如何进行,...

    C标准库源代码C标准库源代码

    在深入研究源代码时,我们可能会遇到一些复杂的实现,如`stdio.h`中的缓冲区管理,`stdlib.h`中的内存分配器,或`math.h`中的浮点数运算优化。这些实现通常涉及操作系统接口、内存模型以及编译器特性,对理解计算机...

    C语言函数头文件大全

    函数头文件通常以`.h`为扩展名,用于在源代码中引入所需的函数、常量、数据类型等,确保编译器知道如何处理这些元素。本资源“C语言函数头文件大全”提供了一个全面的参考,包含了C语言常用的标准库函数和一些常见的...

    C标准库源代码(很全)

    通过分析这些源代码,我们可以看到如何实现标准库中定义的功能,比如`printf`内部是如何处理格式化的,`malloc`是如何管理内存的,以及`strcat`是如何合并字符串的。此外,源代码也可能包含了一些测试用例,帮助我们...

    电子-C标准库源代码.zip

    这个名为"电子-C标准库源代码.zip"的压缩包文件包含的是C标准库的源代码,对于深入理解和学习C语言,以及计算机科学的基本原理具有极大的价值。 C标准库主要由ISO/IEC 9899标准定义,通常被称为C99或C11标准,这些...

    C语言头文件

    自定义头文件通常以`.h`为扩展名,通过`#include`指令在源代码中引入。 例如,`myfunc.h`可能包含如下内容: ```c #ifndef MYFUNC_H #define MYFUNC_H int add(int a, int b); void print_array(int arr[], int ...

    c89标准头文件

    7. `&lt;stdarg.h&gt;`:变长参数头文件,支持可变参数列表的函数,如`printf`的变体`vprintf`。 8. `&lt;float.h&gt;`:浮点数特性头文件,定义了浮点数相关的常量,如`FLT_MAX`。 9. `&lt;limits.h&gt;`:整数类型限制头文件,定义...

    泊松曲面重建论文源码分析PoissonRecon.cpp.txt

    在本文档中,我们将深入分析实现泊松曲面重建算法的源代码 `PoissonRecon.cpp`,理解其核心思想与具体实现细节。 #### 核心知识点详解 ##### 1. 引入头文件与平台兼容性处理 ```c++ 1#include&lt;stdio.h&gt; 2#include...

    用C语言设计计算器程序源代码

    - **`stdarg.h`**:用于可变参数列表的函数。 - **`graphics.h`**:用于图形输出的库,通常与Borland C++编译器配套使用。 - **`string.h`**:提供字符串操作函数,如字符串复制、比较等。 - **`ctype.h`**:字符...

    ISOC头文件

    在C语言中,头文件的作用是为源代码提供预编译的声明,使得编译器在处理源代码时能够知道函数的存在、参数类型以及变量的定义等信息。ISOC头文件通常以`.h`为后缀,例如`&lt;stdio.h&gt;`、`&lt;stdlib.h&gt;`、`&lt;string.h&gt;`等,...

    C和C++头文件,函数和关键字的使用和比较

    这些头文件通过`#include`指令被引入到源代码中,以提供必要的功能。本篇文章将深入探讨C和C++中常用的头文件,以及它们提供的函数和关键字的使用。 首先,`&lt;assert.h&gt;`头文件提供了`assert()`宏,它用于断言程序中...

    C函数库 C语言库下载

    例如,要使用&lt;stdio.h&gt;库中的函数,需要在源代码中包含相应的头文件: ```c #include &lt;stdio.h&gt; ``` 然后就可以使用库中的函数,比如打印"Hello, World!": ```c #include &lt;stdio.h&gt; int main() { printf(...

    c语言实现 log.rar

    在日志实现中,`glog.cpp`和`glog.h`可能是包含实际日志功能实现和接口定义的源代码文件。`glog.h`将定义日志函数的原型,而`glog.cpp`则会实现这些函数的逻辑。通常,日志函数会有一个固定的参数,比如日志级别(如...

    C语言本地头文件库include文件

    7. 其他:`&lt;stdarg.h&gt;`支持可变参数列表,`&lt;float.h&gt;`定义了浮点数相关的常量和宏,`&lt;limits.h&gt;`定义了各种类型的最小值和最大值。 值得注意的是,由于本地化和多字节字符集(如Unicode)的功能在C语言标准库中不是...

    微软字符处理安全类strsafe

    3. stdarg.h:这是一个标准的C库头文件,包含了stdarg宏,用于处理可变参数列表。虽然不是StrSafe库的一部分,但它可能在使用某些StrSafe函数时需要,特别是那些接受可变数量参数的函数,如vprintf系列。 4. strsafe...

    linux主目录文件的含义

    - `stdarg.h`:可变参数列表支持。 - `stddef.h`:标准定义如`NULL`等。 - `string.h`:字符串处理函数。 - `termios.h`:终端I/O结构体定义。 - `time.h`:时间相关函数。 - `unistd.h`:POSIX标准库定义。 ...

Global site tag (gtag.js) - Google Analytics