va_list & va_start & va_arg & va_end 梦里梦外; 2022-08-24 11:10 152阅读 0赞 va\_list 属于变量 而 va\_start & va\_arg & va\_end C语言中解决变参问题的一组宏。头文件来自stdarg.h。 查看linux系统源码方式我一般用locate stdarg.h,然后找到提示目录vi进去。源文件定义是: ![SouthEast][] 在Mac 下追踪头文件也会发现如下宏定义: typedef \_\_darwin\_va\_list va\_list; typedef \_\_builtin\_va\_list \_\_darwin\_va\_list; /\* va\_list \*/ 本质上都是\_\_builtin\_va\_list va\_list是一个字符指针,可以理解为指向当前参数的一个指针,取参必须通过这个指针进行。 <Step 1> 在调用参数表之前,应该定义一个 va\_list类型的变量,以供后用(假设这个 va\_list 类型变量被定义为ap); <Step 2> 然后对 ap进行初始化,让它指向可变参数表里面的第一个参数。这是通过 va\_start 来实现的,其第一个参数是 ap本身, 第二个参数是在变参表前面紧挨着的一个变量; <Step 3> 然后是获取参数,调用 va\_arg。它的第一个参数是ap,第二个参数是要获取的参数的指定类型,并返回这个指定类型的值, 同时把 ap 的位置指向变参表的下一个变量位置; <Step 4> 获取所有的参数之后,我们有必要将这个 ap指针关掉,以免发生危险,方法是调用 va\_end。它是将输入的参数 ap 置为NULL, 应该养成获取完参数表之后关闭指针的习惯。 示例一: void simple_va_fun(int i, ...) { va_list arg_ptr; va_start(arg_ptr, i); int num1 = va_arg(arg_ptr, int); int num2 = va_arg(arg_ptr, int); va_end(arg_ptr); printf("%d %d %d /n", i, num1, num2); return; } 示例二: // Quick Information Display void show(id formatstring,...) { va_list arglist; if (!formatstring) return; va_start(arglist, formatstring); id outstring = [[[NSString alloc] initWithFormat:formatstring arguments:arglist] autorelease]; va_end(arglist); UIAlertView *av = [[[UIAlertView alloc] initWithTitle:@"LEAK DEMO" message:outstring delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] autorelease]; [av show]; } - (void) intro { show(@"Run with Instruments using Leaks. Click a button to leak memory.%@\n",@"zyjzyj"); } 示例三: #define showAlert(format, ...) myShowAlert(__LINE__, (char *)__FUNCTION__, format, ##__VA_ARGS__) // Simple Alert Utility void myShowAlert(int line, char *functname, id formatstring,...) { va_list arglist; if (!formatstring) return; va_start(arglist, formatstring); id outstring = [[[NSString alloc] initWithFormat:formatstring arguments:arglist] autorelease]; va_end(arglist); NSString *filename = [[NSString stringWithCString:__FILE__ encoding:NSUTF8StringEncoding] lastPathComponent]; NSString *debugInfo = [NSString stringWithFormat:@"%@:%d\n%s", filename, line, functname]; UIAlertView *av = [[[UIAlertView alloc] initWithTitle:outstring message:debugInfo delegate:nil cancelButtonTitle:@"OK"otherButtonTitles:nil] autorelease]; [av show]; } - (void) rightAction: (id) sender { showAlert(@"You pressed the right button"); } 在C语言中,它们的详细定义如下: 1) va\_list型变量: \#ifdef \_M\_ALPHA typedef struct \{ char \*a0; /\* pointer to first homed integer argument \*/ int offset; /\* byte offset of next parameter \*/ \} va\_list; \#else typedef char \* va\_list; \#endif 2)\_INTSIZEOF 宏,获取类型占用的空间长度,最小占用长度为int的整数倍: \#define \_INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) 3)VA\_START宏,获取可变参数列表的第一个参数的地址(ap是类型为va\_list的指针,v是可变参数最左边的参数): \#define va\_start(ap,v) ( ap = (va\_list)&v + \_INTSIZEOF(v) ) 4)VA\_ARG宏,获取可变参数的当前参数,返回指定类型并将指针指向下一参数(t参数描述了当前参数的类型): \#define va\_arg(ap,t) ( \*(t \*)((ap += \_INTSIZEOF(t)) - \_INTSIZEOF(t)) ) 5)VA\_END宏,清空va\_list可变参数列表: \#define va\_end(ap) ( ap = (va\_list)0 ) 进一步解释: va\_list arg\_ptr:定义一个指向个数可变的参数列表指针; va\_start(arg\_ptr, argN):使参数列表指针arg\_ptr指向函数参数列表中的第一个可选参数, 说明:argN是位于第一个可选参数之前的固定参数,(或者说,最后一个 固定参数;…之前的一个参数), 函数参数列表中参数在内存中的顺序与函数声明时的顺序是一致的。如果有一va函数的声明是 void va\_test(char a, char b, char c, …),则它的固定参数依次是a,b,c,最后一个固定参数argN为c,因此就是va\_start(arg\_ptr, c)。 va\_arg(arg\_ptr, type):返回参数列表中指针arg\_ptr所指的参数,返回类型为type,并使指针arg\_ptr指向参数列表中下一个参数。 va\_copy(dest, src):dest,src的类型都是va\_list,va\_copy()用于复制参数列表指针,将dest初始化为src。 va\_end(arg\_ptr):清空参数列表,并置参数指针arg\_ptr无效。说明:指针arg\_ptr被置无效后,可以通过调用 va\_start ()、va\_copy()恢复arg\_ptr。每次调用va\_start() / va\_copy()后,必须得有相应的va\_end()与之匹配。 参数指针可以在参数列表中随意地来回移动,但必须在va\_start() … va\_end()之内。 va函数的实现就是对参数指针的使用和控制。这里,移动指针使其指向下一个参数,那么移动指针时的偏移量是多少呢, 没有具体答案,因为这里涉及到内存对齐(alignment)问题,内存对齐跟具体 使用的硬件平台有密切关系, 比如大家熟知的32位x86平台规定所有的变量地址必须是4的倍数(sizeof(int) = 4)。 va机制中用宏\_INTSIZEOF(n)来解决这个问题,没有这些宏,va的可移植性无从谈起。 参考内容来源: 初级篇: http://blog.sina.com.cn/s/blog\_590be5290100qhxr.html http://justsee.iteye.com/blog/1637173 http://www.cnblogs.com/rainduck/archive/2010/11/10/1873417.html http://www.cnblogs.com/margincc/archive/2011/03/29/2095057.html\#undefined 进阶篇: http://www.cnblogs.com/diyunpeng/archive/2010/01/09/1643201.html http://blog.csdn.net/ritaday/article/details/6718353(强烈推荐) http://www.cocoawithlove.com/2009/05/variable-argument-lists-in-cocoa.html (英文还可以的话,强烈推荐) http://blog.csdn.net/skymingst/article/details/36872003 (转载的上篇英文,原文打不开连接的参考下) [SouthEast]: /images/20220823/cc2ed987d04141868b3e34a770e49716.png
相关 valist:解决变参问题 1. 概述 va\_list 是在 C 语言中引入解决变参问题的一组宏,变参问题是指参数的个数不定或者每个参数的类型不同。 头文件: include < 水深无声/ 2022年05月17日 00:04/ 0 赞/ 225 阅读
还没有评论,来说两句吧...