文章标题
来源:互联网 发布:单片机开发板哪个好 编辑:程序博客网 时间:2024/05/29 03:32
可变函数参数复习
首先,来看一个可变参数函数:
#include <stdio.h>#include <stdarg.h>int Max(int n,...);//可变参数函数,求最大值 int main(int argc,char *argv[]){ int max=Max(5,2,1,6,3,5) ; printf("%d\n",max); return 0;}int Max(int n,...){ int i=0,max=0,num=0; va_list arg; //与 cahr *arg;等价 va_start(arg,n); //arg指向第一个可变参数 2 max=va_arg(arg,int); for(i=0;i<n;i++) { num=va_arg(arg,int); if(max<num) { max=num; } } va_end(arg); //arg=NULL; return max;}
这个函数很简单,就是求最大值。特点就是可以输入任意个参数,而没有像以往的函数一样固定参数个数。
查看代码,我们发现几个没见过的东东:
**va_list
va_start
va_arg
va_end
“…”符号**
声明一下,这些都不是函数,而是宏定义
va–variable argument(可变的参数)
(1)va_list
查看stdarg.h文件
typedf char* va_list;
所以,va_list其实是一个指向char类型的指针。
(2)va_start()
查看stdarg.h文件
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
再次强调,这是宏,宏,宏!不是函数!
看到有点头大吧!来,分析分析:
首先:
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
[推荐答案]
_INTSIZEOF(n)整个做的事情就是将n的长度化为int长度的整数倍。
比如n为5,二进制就是101b,int长度为4,二进制为100b,那么n化为int长度的整数倍就应该为8。
~(sizeof(int) - 1) )就应该为~(4-1)=~(00000011b)=11111100b,这样任何数& ~(sizeof(int) - 1) )后最后两位肯定为0,就肯定是4的整数倍了。
(sizeof(n) + sizeof(int) - 1)就是将大于4m但小于等于4(m+1)的数提高到大于等于4(m+1)但小于4(m+2),这样再& ~(sizeof(int) - 1) )后就正好将原长度补齐到4的倍数了。
原文地址:
http://blog.csdn.net/sdcxyz/article/details/7067699
我们知道对于IX86,sizeof(int)一定是4的整数倍,所以~(sizeof(int) - 1) )的值一定是 右面[sizeof(n)-1]/2位为0,整个这个宏也就是保证了右面[sizeof(n)-1]/2位为0,其余位置
为1,所以_INTSIZEOF(n)的值只有可能是4,8,16,……等等,实际上是实现了字节对齐。
_INTSIZEOF(n) 的目的在于把sizeof(n)的结果变成至少是sizeof(int)的整倍数,这个一般用来在结构中实现按int的倍数对齐
如果sizeof(int)是4,那么,当sizeof(n)的结果在1~4之间是,_INTSIZEOF(n)的结果会是4;当sizeof(n)的结果在5~8时,
_INTSIZEOF(n)的结果会是8;当sizeof(n)的结果在9~12时,_INTSIZEOF(n)的结果会是12;……总之,会是sizeof(int)的倍数。
走远了,再回来讲va_start():
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
ap是类型为va_list的指针,v是可变参数最左边的参数,亦即最后一个固定参数。
运行完这句代码后,ap指向第一个可变参数在堆栈中的地址。
|————————————————|高地址
|————-函数返回地址——————|
|————……………………..—————–|
|————————————————|<–va_arg后ap指向下一个参数
|—– 第n个参数(第一个可变参数)—–|
|————————————————|<–va_start后ap指向第一个可变参数
|— 第n-1个参数(最后一个固定参数)—-|
|————————————————|<–&v 低地址
所以,va_start(arg,n);运行后,arg指向了第一个可变参数“2”。
(3)va_arg(arg,int)
#define va_arg(ap,t) (*(t*)((ap+=_INTSIZEOF(t))- _INTSIZEOF(t)))
va_arg()取可变参数的值。
代码精髓:
( t )((ap+=_INTSIZEOF( t ) ) - _INTSIZEOF(t))
首先,ap += sizeof( t ),ap已经指向下一个参数的地址了(ap的值改变);
然后,ap-sizeof( t ),又返回前一个参数了(ap的值没有改变),用*取出参数的值。
一句代码,其实执行了两步,妙哉妙哉!
(4)va_end(arg)
#define va_end(ap) ( ap = (va_list)0 )
使ap不再指向堆栈,而是跟NULL一样。
OK,关于可变函数参数就到这了!
思考:printf()怎么实现的呢!写出自己的myprintf()函数吧!
- 文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题 文章标题 文章标题 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 高级查询
- 变分算法-应用
- 实验 记住密码
- 两位数码管显示
- 【Spring】Spring基础配置-AOP
- 文章标题
- blog_echo_day1
- Codeforces Round #292 DIV2 题解
- 矩阵连乘
- oracle11g客户端如何完全卸载
- Android之股票开发学习
- 自己实现ls命令
- LayoutInflater 详解
- aidl实现Android系统语言切换