19、关于va_list,va_start,va_arg,va_end

简介: 前面,我总结过关于va_list,va_start,va_arg,va_end的一些知识点: http://www.cnblogs.com/mydomain/archive/2010/07/27/1785667.

前面,我总结过关于va_list,va_start,va_arg,va_end的一些知识点:<?xml:namespace prefix = o />

http://www.cnblogs.com/mydomain/archive/2010/07/27/1785667.html

http://www.cnblogs.com/mydomain/archive/2010/12/06/1898140.html

今天看到一篇文件,写的也言简意赅,喜欢就转载一下,原谅地址是:

http://www.cnblogs.com/wubiyu/archive/2008/07/30/1256860.html

不过,本文中,这一句“(2va_arg()取得类型t的可变参数值,在这步操作中首先apt = sizeof(t类型),让ap指向下一个参数的地址。然后返回ap-sizeof(t类型)t类型*指针,这正是第一个可变参数在堆栈里的地址。然后用*取得这个地址的内容。”没有介绍清楚,具体参见

#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

第一个地址所链接文章。

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指向第一个可变参数在堆栈的地址。

2va_arg()取得类型t的可变参数值,在这步操作中首先apt = sizeof(t类型),让ap指向下一个参数的地址。然后返回ap-sizeof(t类型)t类型*指针,这正是第一个可变参数在堆栈里的地址。然后用*取得这个地址的内容。

3va_end(),x86平台定义为ap = ((char*)0),使ap不再指向堆栈,而是跟null一样,有些直接定义为((void*)0),这样编译器不会为va_end产生代码,例如 gcclinuxx86平台就是这样定义的。

要注意的是:由于参数的地址用于va_start宏,所以参数不能声明为寄存器变量,或作为函数或数组类型。

使用va_list应该注意的问题:

1)因为va_start, va_arg, va_end等定义成宏,可变参数的类型和个数完全在该函数中由程序代码控制,它并不能智能地识别不同参数的个数和类型,也就是说,你想实现智能识别可变参数的话是要通过在自己的程序里作判断来实现。

2)另外有一个问题,因为编译器对可变参数的函数的原型检查不够严格,对编程查错不利.不利于我们写出高质量的代码。

小结:可变参数的函数原理其实很简单,而va系列是以宏定义来定义的,实现跟堆栈相关。我们写一个可变函数的c函数时,有利也有弊,所以在不必要的场合,我们无需用到可变参数,如果在c++里,我们应该利用c++多态性来实现可变参数的功能,尽量避免用c语言的方式来实现。

目录
相关文章
va_list,va_start,va_arg,va_en
   在代码中常见到可变参数。截取一段cocos2d-x的代码:     CCArray* CCArray::create(CCObject* pObject, ...) { va_list args; // 这个变量是指向参数的指针,typedef char *  va_list va_start(args,pObject);// 初始化args指针,第二个参数存放第
1001 0
|
6月前
|
安全 Java
java线程之List集合并发安全问题及解决方案
java线程之List集合并发安全问题及解决方案
982 1
|
5月前
|
Java API Apache
怎么在在 Java 中对List进行分区
本文介绍了如何将列表拆分为给定大小的子列表。尽管标准Java集合API未直接支持此功能,但Guava和Apache Commons Collections提供了相关API。
|
5月前
|
运维 关系型数据库 Java
PolarDB产品使用问题之使用List或Range分区表时,Java代码是否需要进行改动
PolarDB产品使用合集涵盖了从创建与管理、数据管理、性能优化与诊断、安全与合规到生态与集成、运维与支持等全方位的功能和服务,旨在帮助企业轻松构建高可用、高性能且易于管理的数据库环境,满足不同业务场景的需求。用户可以通过阿里云控制台、API、SDK等方式便捷地使用这些功能,实现数据库的高效运维与持续优化。
|
5月前
|
存储 安全 Java
详解Java中集合的List接口实现的ArrayList方法 | Set接口实现的HashSet方法
详解Java中集合的List接口实现的ArrayList方法 | Set接口实现的HashSet方法
|
6月前
|
Java API
使用 Java 来实现两个 List 的差集操作
使用 Java 来实现两个 List 的差集操作
186 3
|
5月前
|
存储 Java 索引
Java List接口实现原理与性能评估
Java List接口实现原理与性能评估
|
5月前
|
存储 缓存 安全
Java List操作详解及常用方法
Java List操作详解及常用方法