《C语言接口与实现》实验——可变参数表的使用(va_list, va_start, va_arg, va_end)
来源:互联网 发布:大型游戏下载软件 编辑:程序博客网 时间:2024/05/18 16:59
《C语言接口与实现》作为接口库,源文件中大量使用了可变参数表,这些到底是怎么使用的?先来看这几个例子,基本明白了可变参数表使用。后面部分从网上整理了原理:
源程序:
#include <stdio.h>#include <stdarg.h>#include <string.h>//// 使用示例1:追加串// void Va_Fn1(char *dest, char *data, ...){va_list ap;char *p = data;//指向第一个可变参数//第二个参数就是写 ... 前面那个va_start(ap, data);//遍历每一个可变参数,取出来使用while(1){//访问当前这个可变参数,先用,后遍历!!strcat(dest, p);p = va_arg(ap, char *);if (p == NULL) break;}//结束va_end(ap);}//// 使用示例2:累加和// int Va_Fn2(int a, ...){int ret = a;//指向第一个参数int sum = 0;va_list ap;//第二个参数就是写 ... 前面那个va_start(ap, a);//遍历每一个可变参数,取出来使用while(1){//先用,后遍历sum += ret;ret =va_arg(ap, int);if (ret == -1) break;}//结束va_end(ap);return sum;}//// 使用示例3:使用数据结构// typedef struct{int x;int y;}MY_TYPE;void Va_Fn3(int n, MY_TYPE *p, ...){int i = 0;va_list ap;MY_TYPE *tmp = p;//第二个参数就是写 ... 前面那个va_start(ap, p);for(; i<n; i++){printf("\t%d-----%d\n", tmp->x, tmp->y);tmp = va_arg(ap, MY_TYPE *);}//结束va_end(ap);}//// 使用示例4:稍复杂的可变参数表//(char *, int, int),(char *, int, int), ......// void Va_Fn4(char *msg, ...){va_list ap;int i, j;char *str = msg;//指向第一个参数//第二个参数就是写 ... 前面那个va_start(ap, msg);while(1){//使用可变参数表,先使用i = va_arg(ap, int);j = va_arg(ap, int);printf("\t%s---%d----%d\n", str, i, j);//后遍历str = va_arg(ap, char *);//第二个参数是【可变参数】的类型if (str == NULL) break;}//结束va_end(ap);}void main(){//示例1char dest[1000] = {0};Va_Fn1(dest, "Hello ", "OK ", "欢迎 ", "Yes ", NULL);printf("示例1 = %s\n", dest);//示例2int x = Va_Fn2(9, 9, 1, 3, 90, -1);printf("示例2 = %d\n", x);//示例3MY_TYPE a, b, c;a.x = 100;a.y = 300;b.x = 1100;b.y = 1300;c.x = 6100;c.y = 6300;printf("示例3:\n");Va_Fn3(3, &a, &b, &c);//示例4printf("示例4:\n");Va_Fn4("Hello", 1, 2, "XYZ", 300, 600, "ABC", 77, 88, NULL);}
输出:
示例1 = Hello OK 欢迎 Yes示例2 = 112示例3: 100-----300 1100-----1300 6100-----6300示例4: Hello---1----2 XYZ---300----600 ABC---77----88Press any key to continue
原理:
1. 函数参数是以数据结构:栈的形式存取,从右至左入栈
2. 首先是参数的内存存放格式:参数存放在内存的堆栈段中,在执行函数的时候,从最后一个开始入栈。因此栈底高地址,栈顶低地址,举个例子如下:
void func(int x, float y, charz);
那么,调用函数的时候,实参char z 先进栈,然后是 float y,最后是 intx,因此在内存中变量的存放次序是 x->y->z,因此,从理论上说,我们只要探测到任意一个变量的地址,并且知道其他变量的类型,通过指针移位运算,则总可以顺藤摸瓜找到其他的输入变量。<----这就是原理!!
3. 看源码(vc98/include/stdarg.h):(注意是X86相关的,不是mips,不是ALPHA的,不是PPC等等的!)
typedef char * va_list;
#ifdef _M_IX86
#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 )
#elif defined(_M_MRX000)
这里有复杂的宏,展开它:在“工程属性” —〉“C/C++”—〉“Project Options” 手工填入/P,然后rebuild,会产生于.cpp同名的.i文件,里面的宏被展开了。来看展开后的第一个函数:
void Va_Fn1(char *dest, char *data, ...){va_list ap;char *p = data;( ap = (va_list)&data + ( (sizeof(data) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) );while(1){strcat(dest, p);p = ( *(char * *)((ap += ( (sizeof(char *) + sizeof(int) - 1) & ~(sizeof(int) - 1) )) - ( (sizeof(char *) + sizeof(int) - 1) & ~(sizeof(int) - 1) )) );if (p == 0) break;}( ap = (va_list)0 );}
再看展开的第二个函数,这个较简单:
int Va_Fn2(int a, ...){int ret = a;int sum = 0;va_list ap;( ap = (va_list)&a + ( (sizeof(a) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) );while(1){sum += ret;ret =( *(int *)((ap += ( (sizeof(int) + sizeof(int) - 1) & ~(sizeof(int) - 1) )) - ( (sizeof(int) + sizeof(int) - 1) & ~(sizeof(int) - 1) )) );if (ret == -1) break;}( ap = (va_list)0 );return sum;}
- 《C语言接口与实现》实验——可变参数表的使用(va_list, va_start, va_arg, va_end)
- C语言中可变参数的用法——va_list、va_start、va_arg、va_end参数定义
- C语言中可变参数的用法——va_list、va_start、va_arg、va_end参数定义
- C语言中可变参数的用法——va_list、va_start、va_arg、va_end参数定义
- C语言中可变参数的用法——va_list、va_start、va_arg、va_end参数定义
- C语言中可变参数的用法——va_list、va_start、va_arg、va_end参数定义
- C语言中可变参数的用法——va_list、va_start、va_arg、va_end参数定义
- C语言中可变参数的用法——va_list、va_start、va_arg、va_end参数定义
- C语言中的可变参数:va_list ,va_start,va_arg,va_end
- C语言可变参数,va_arg、va_list,va_start,va_end,_INTSIZEOF
- 深入C语言可变参数(va_arg,va_list,va_start,va_end,_INTSIZEOF)
- C语言可变参数--va_list、va_start、va_arg、va_end
- 深入C语言可变参数(va_arg,va_list,va_start,va_end)
- va_list、va_start、va_arg、va_end的原理与使用 (转)
- va_list、va_start、va_arg、va_end的原理与使用 (转)
- C语言利用va_list、va_start、va_end、va_arg宏定义可变参数的函数
- C语言va_list,va_start,va_arg,va_end解析
- C语言va_list,va_start,va_arg,va_end
- MAM example
- SID,PID,SPID,UID.....咋这么多ID...
- 书摘---创业36条军规5:如何选择创业方向
- xml,让后利用chome打开
- unlable to lock the administrator
- 《C语言接口与实现》实验——可变参数表的使用(va_list, va_start, va_arg, va_end)
- java源码笔记之String
- GetMemory
- MVC与三层架构
- PE文件格式及相关资料
- xml(在内部定义,上一篇是在外部引入)
- FormsAuthentication.HashPasswordForStoringInConfigFile 方法 之研究
- C++中的const与指针
- 解题报告之DisjointSet