在VC++6.0的include有一个stdarg.h头文件,有如下几个宏定义:
#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //第一个可选参数地址
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一个参数地址
#define va_end(ap) ( ap = (va_list)0 ) // 将指针置为无效
===================================================
有关VA_LIST的用法:
VA_LIST 是在C语言中解决变参问题的一组宏
VA_LIST的用法:
(1)首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针
(2)然后用VA_START宏初始化变量刚定义的VA_LIST变量,这个宏的第二个参数是第一个可变参数的前一个参数,是一个固定的参数。
(3)然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型。
(4)最后用VA_END宏结束可变参数的获取。然后你就可以在函数里使用第二个参数了。如果函数有多个可变参数的,依次调用VA_ARG获取各个参数。
VA_LIST在编译器中的处理:
(1)在运行VA_START(ap,v)以后,ap指向第一个可变参数在堆栈的地址。
(2)VA_ARG()取得类型t的可变参数值,在这步操作中首先apt = sizeof(t类型),让ap指向下一个参数的地址。然后返回ap-sizeof(t类型)的t类型*指针,这正是第一个可变参数在堆栈里的地址。然后用*取得这个地址的内容。
(3)VA_END(),X86平台定义为ap = ((char*)0),使ap不再指向堆栈,而是跟NULL一样,有些直接定义为((void*)0),这样编译器不会为VA_END产生代码,例如gcc在Linux的X86平台就是这样定义的。
要注意的是:由于参数的地址用于VA_START宏,所以参数不能声明为寄存器变量,或作为函数或数组类型。
使用VA_LIST应该注意的问题:
(1)因为va_start, va_arg, va_end等定义成宏,所以它显得很愚蠢,可变参数的类型和个数完全在该函数中由程序代码控制,它并不能智能地识别不同参数的个数和类型. 也就是说,你想实现智能识别可变参数的话是要通过在自己的程序里作判断来实现的.
(2)另外有一个问题,因为编译器对可变参数的函数的原型检查不够严格,对编程查错不利.不利于我们写出高质量的代码。
小结:可变参数的函数原理其实很简单,而VA系列是以宏定义来定义的,实现跟堆栈相关。我们写一个可变函数的C函数时,有利也有弊,所以在不必要的 场合,我们无需用到可变参数,如果在C++里,我们应该利用C++多态性来实现可变参数的功能,尽量避免用C语言的方式来实现。
===================================================
变长参数应用举例:
先得声明一个变长参数的变量va_list list
在使用前要先用va_start(list, last_param)对list进行初始化,last_param为最右边的已知参数,表示list
从last_param的下一个参数开始
va_arg(list, 类型)
最后不要忘了用va_end(list)
分享到:
相关推荐
### stdarg.h中三个宏va_start,va_arg和va_end...通过以上介绍,我们可以看到`va_start`、`va_arg`和`va_end`这三个宏如何协同工作来处理可变数量的参数。这对于编写灵活的、能够接受任意数量参数的函数是非常有用的。
### va_start、va_end、va_list的详细使用方法 #### 概述 在C语言中,函数参数的数量通常是固定的。然而,在某些情况下,我们可能希望一个函数能够接收可变数量的参数。例如,`printf`函数就是一个很好的例子,它...
### C语言可变参数机制详解:`va_list`与`vsnprintf`及`printf`实现 #### 引言 在C语言编程中,我们经常使用`printf`函数来输出各种格式的数据,但你是否曾思考过,这个看似简单的函数背后隐藏着怎样的复杂性?`...
本文详细介绍了C语言中可变参数函数的实现机制,包括`_va_list`的使用方法,以及如何基于这些机制构建自己的可变参数函数,如简易的`printf`函数。通过理解`_va_list`和`vsnprintf`等函数的工作原理,开发者可以更好...
在C语言中,`va_arg`是一个非常重要的函数宏,它是可变参数列表(Variable Argument List,也称为 variadic function)处理的关键组成部分。标题“va_arg_c_”可能指的是一个文档,专门探讨了如何在C语言中使用`va_...
写可变参数的C函数要在程序中用到以下这些宏: 代码如下:void va_start( va_list arg_ptr, prev_param );type va_arg( va_list arg_ptr, type );void va_end( va_list arg_ptr );va在这里是variable-argument(可变...
1. 因为va_start, va_arg, va_end等定义成宏,所以它显得很愚蠢, 可变参数的类型和个数完全在该函数中由程序代码控制,它并不能智能地识别不同参数的个数和类型。 2. 另外还有一个问题,因为编译器对可变参数的函数...
可变参数函数的实现主要包括几个宏:va_list, va_start, va_arg, va_end。下面将详细讲解这些宏以及它们的用法: 1. va_list: 这个类型用于声明一个变量,该变量会被用来遍历参数列表。在stdarg.h中,va_list被定义...
在使用可变参数之前,你需要定义一个`va_list`类型的变量,例如`va_list arg_ptr`,用来存储和遍历可变参数列表。 2. `va_start`: `va_start`宏用于初始化`va_list`指针,使其指向可变参数列表的开始。它的两个...
本文讨论了C语言中可变参数的用法,包括如何写一个简单的可变参数的C函数,如何使用可变参数宏va_start、va_arg和va_end,以及可变参数在编译器中的处理。 一、写一个简单的可变参数的C函数 在C语言中,某些函数...
这里的`ap`是一个指向可变参数列表的指针(通常是一个`va_list`类型的变量),`last_fixed_arg`是可变参数列表前的最后一个固定参数。`va_start`宏会将`ap`指向`last_fixed_arg`后面的第一个可变参数。 例如,我们...
2. 使用`stdarg.h`库(C)或`<cstdarg>`库(C++)处理可变参数的三个关键宏:`va_start`、`va_arg`和`va_end`。 3. 如何在函数中定义和使用`va_list`,以及如何正确处理参数类型。 4. 通过实例展示了如何创建一个...
va_start宏用于初始化可变参数表,va_arg宏用于取得当前的可变参数,va_end宏用于结束可变参数的使用。 va_start宏的原型为:void va_start(va_list ap, prev_param),其中ap是指向可变参数表的指针,prev_param是前...
在C语言中,可变参数的实现基于调用约定(calling convention),通常涉及到两个关键函数:`va_start`、`va_end` 和一个宏 `va_list`。`va_list` 是一个类型定义,用于存储可变参数列表的指针;`va_start` 用于初始...
这个头文件中定义了`va_list`、`va_start`、`va_arg`和`va_end`宏,它们是处理可变参数列表的关键。下面逐一解释这些宏的作用: 1. `va_list`: 这是一个类型定义,用来声明一个可变参数列表的变量。例如:`va_list ...
在这个例子中,`print_values`函数接收一个整数`num_args`,表示参数的数量,然后通过`va_start`初始化`va_list`,`va_arg`依次获取每个参数的值,最后用`va_end`清理。 总结来说,`#`、`##` 和 `__VA_ARGS__` 在C/...
在C语言中,通过宏`va_start`、`va_arg`和`va_end`来处理这些可变参数。这些宏定义在`stdarg.h`头文件中,因此编写可变参数函数时需要包含此头文件。 #### 宏定义解析 1. **`va_start`**: 初始化可变参数列表的...
这个头文件包含了一些关键的函数和类型定义,如`va_list`、`va_start`、`va_arg`和`va_end`,它们是处理可变参数的关键。 1. `va_list`:这是一个类型定义,用于存储可变参数列表的指针。通常我们会声明一个`va_...