编程入门:浅谈C语言的可变参数
下面请跟着图老师小编一起来了解下编程入门:浅谈C语言的可变参数,精心挑选的内容希望大家喜欢,不要忘记点个赞哦!
typedef char * va_list; #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 ) _INTSIZEOF(n)宏是为了考虑那些内存地址需要对齐的系统,从宏的名字来应该是跟sizeof(int)对齐。一般的sizeof(int)=4,也就是参数在内存中的地址都为4的倍数。比如,假如sizeof(n)在1-4之间,那么_INTSIZEOF(n)=4;假如sizeof(n)在5-8之间,那么_INTSIZEOF(n)=8。 为了能从固定参数依次得到每个可变参数,va_start,va_arg充分利用下面两点: 1. C语言在函数调用时,先将最后一个参数压入栈 2. X86平台下的内存分配顺序是从高地址内存到低地址内存 高位地址 第N个可变参数 。。。 第二个可变参数 第一个可变参数 ? ap 固定参数 ? v 低位地址 由上图可见,v是固定参数在内存中的地址,在调用va_start后,ap指向第一个可变参数。这个宏的作用就是在v的内存地址上增加v所占的内存大小,这样就得到了第一个可变参数的地址。 接下来,可以这样设想,假如我能确定这个可变参数的类型,那么我就知道了它占用了多少内存,依葫芦画瓢,我就能得到下一个可变参数的地址。 让我再来看看va_arg,它先ap指向下一个可变参数,然后减去当前可变参数的大小即得到当前可变参数的内存地址,再做个类型转换,返回它的值。 要确定每个可变参数的类型,有两种做法,要么都是默认的类型,要么就在固定参数中包含足够的信息让程序可以确定每个可变参数的类型。比如,printf,程序通过分析format字符串就可以确定每个可变参数大类型。 最后一个宏就简单了,va_end使得ap不再指向有效的内存地址。 看了这几个宏,不禁让我再次感慨,C语言太灵活了,而且代码可以写得非常简洁,虽然有时候让人看得不是很明白,但是一旦明白 过来,你肯定会为它击掌叫好! 其实在varargs.h头文件中定义了UNIX System V实行的va系列宏,而上面在stdarg.h头文件中定义的是ANSI C形式的宏,这两种宏是不兼容的,一般说来,我们应该使用ANSI C形式的va宏。