关于INTSIZEOF宏是怎么来的已经解释过了, 这里简要概述一下,宏定义如下:
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
当sizeof(n)<4时&#xff0c;宏的值就是4&#xff0c;当sizeof(n)>4时&#xff0c;宏的值就是4的倍数。
这里主要介绍两个宏va_start和va_arg两个宏&#xff0c;先说这个va_start。
宏定义如下&#xff1a;
#define va_start(ap,v) ( ap &#61; (va_list)&v &#43; _INTSIZEOF(v) )&#xff0c;这里的va_list的类型是
char *&#xff0c;v是输入的第一个参数。首先在理解这个宏的前提要理解函数的形参是如何存储&#xff0c;这里我们做个试验如下图所示
形参是存储在栈里面的&#xff0c;栈的高地址在上&#xff0c;低地址在下&#xff0c;那么由上图可以得到的是&#xff0c;x&#xff0c;y&#xff0c;z在栈中存储的结构从上到下依次为z&#xff0c;y&#xff0c;x。那么(va_list)&v的意思就是取第一个参数的地址并强制转化为char*类型。比如这里的x的地址为1638116(十进制表示的)被强制转化为char*&#xff0c;对于_INTSIZEOF(v)&#xff0c;若是这里的v也为x的话&#xff0c;那么这个宏的值为4。进而两者相加的值就是1638120。这里要说明的是地址的类型为char*的话&#xff0c;地址加1就相当于只是加1&#xff0c;比如这里的1638116 &#43; 4 &#61; 1638120&#xff1b;如果地址的类型是int *那么加1的意思就是地址&#43;1*4。为什么&#xff1f;&#xff1f;&#xff1f;是这样的&#xff1a;比如一个指针指向一个int的输入比如int a[10],那么每一个元素就占4个字节所以地址&#43;1中的1表示1*4&#xff0c;所谓的指针加几就是为了向前或者向后移动&#xff0c;那么移动多少字节就要取决于指针指向的变量的类型了&#xff0c;这样解释明白了吧&#xff01;&#xff01;&#xff01;很基础是吧&#xff0c;比如数组是char型的&#xff0c;那么加1就是地址纯粹的加1了&#xff0c;因为sizeof(char) &#61; 1的嘛。
好了&#xff0c;继续上面说的得到了地址1638116 &#43; 4 &#61; 1638120&#xff0c;那么这个1638120不正好就是y的地址值吗。所以这个宏的功能就是&#xff1a;输入第n个参数&#xff0c;输出的就是第n &#43; 1个参数的地址值。再来介绍va_arg宏&#xff0c;它的定义如下&#xff1a;
#define va_arg(ap,t) ( *(t *)((ap &#43;&#61; _INTSIZEOF(t)) - _INTSIZEOF(t)) )&#xff0c;这里的t输入的是变量的类型&#xff0c;比如int&#xff0c;char等等之类的。ap &#43;&#61; _INTSIZEOF(t)的意思让指针ap指向下一个参数的地址&#xff0c;在强调一遍高地址存的是函数越右边的形参值(因为形参是存在栈中的)&#xff0c;比如假设ap指向的是x的地址&#xff0c;要使得ap指向y&#xff0c;那么由于x是在低地址那么就要加上x的类型&#xff0c;比如这里的x类型为int&#xff0c;所以这个时候ap是指向y的了。再减去_INTSIZEOF(t)(注意此时ap还是指向的y)那么((ap &#43;&#61; _INTSIZEOF(t)) - _INTSIZEOF(t))整个地址值就还原到原来的地方&#xff0c;也就是再次指向了x&#xff0c;为什么又要回来&#xff0c;其实就是为了使得ap指向下一个地址&#xff0c;然后再次回到原来的地址&#xff0c;在经过强制转化(t *)&#xff0c;然后再取值*(t *)的符号“*”。
我们来捋一捋这个过程&#xff0c;假设函数只有x&#xff0c;y&#xff0c;z三个形参&#xff0c;一般先调用va_start使得ap指向了y&#xff0c;然后再调用va_arg&#xff0c;使得ap指向z&#xff0c;由于y的值没取出来进行计算&#xff0c;那么&#xff0c;就要把地址还原也就是上面再减去_INTSIZEOF(t)&#xff0c;在取出y的值。那么这里就有一个问题是x的值并没用到&#xff0c;别急看完下面的例子就明白怎么用x的值了。
我们来举一个例子来应用一下&#xff0c;我们要实现&#xff0c;不管输入多少个参数&#xff0c;使得函数形参从第二个参数开始起进行累加&#xff0c;如下图所示&#xff1a;
function函数形参x表示的是有多少个参数&#xff0c;因为在执行va_start的时候就直接使得ap的指针指向了下一个形参的位置&#xff0c;所以可以利用x的值来表示有多少个参数&#xff0c;比如这里有4个参数&#xff0c;分别为0,1,2,3,4&#xff0c;那么function的功能就是把这几个值相加也就是6了。
举报/反馈