可变参数列表源码剖析及实例解析

来源:互联网 发布:java 跳出for循环 编辑:程序博客网 时间:2024/06/01 10:09

一、源码剖析
在介绍可变参数列表之前,先补充两个宏

1._ADDRESSOF(v)

源码 :

#define _ADDRESSOF(v)   ( &(v) )

作用:对变量v取地址

2._INTSIZEOF(n)

源码:

#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

作用:将n的长度化为int长度的整数倍

原理:上式等于(sizeof(n)+3)&~(3)

其中~(3)=11111111 11111111 11111111 11111100

任何数&~(3)之后的二进制最后两位一定为00

则:如果4*i< num< 4 * (i+1) (i>=0,i∈Z) ,那么 num&~3=4 *(i+1);如果num等于4的整数倍,num&~3=num。

又因为(sizeof(n)+3)>=4;所以将保证把n的长度提升到4的倍数,即化为int长度的整数倍

读懂上面两个宏之后可以继续了解可变参数列表,可变参数列表包括:

1.va_list

源码:

typedef char *  va_list;

也就是说va_list是个char类型指针

2.va_arg

源码:

#define va_arg _crt_va_arg#define _crt_va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

意思:将指针ap指向当前位置移动_INTSIZEOF(t)个字节后的位置,然后取现在的ap所在位置的前 _INTSIZEOF(t)个字节的位置(ap移动前的原位置),并将其强制转换成t类型,然后对其解引用,取出这个地址的内容。

作用:将ap移位_INTSIZEOF(t)个字节后,再取出ap移位前的位置对应的数据

如图:
这里写图片描述
3.va_copy(暂不做解释,后期补充)

源码:

void _CRTIMP __cdecl _vacopy(_Out_ va_list *, _In_ va_list);#define va_copy(apd, aps) _vacopy(&(apd), aps)

4.va_start

源码:

#define va_start _crt_va_start#define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )

作用:对v取地址,并强制转换成va_list即char *类型,再将其移动 _INTSIZEOF(v)个字节后的地址赋给ap

5.va_end

源码:

#define va_end _crt_va_end#define _crt_va_end(ap)      ( ap = (va_list)0 )

作用:将0强制转换成va_list即char *类型,赋给ap,即将ap置空

二、实例解析

#include <stdio.h>#include <stdarg.h>#include <windows.h>int average(int n,...)//n代表参数个数{    int i = 0;    int sum = 0;    va_list arg;    va_start(arg, n);    for (i = 0; i < n;i++)    {        sum += va_arg(arg,int);    }    va_end(arg);    return sum/n;}int main(){    int ret = average(3,5,6,4);    printf("ret= %d\n",ret);    system("pause");    return 0;}

将上面代码转换成我们能看得懂的代码,如下:

#include <stdio.h>#include <stdarg.h>#include <windows.h>int average(int n, ...)//n代表参数个数{    int i = 0;    int sum = 0;    //va_list arg;    char *arg;    //va_start(arg, n);    //arg = (char *)_ADDRESSOF(n) + _INTSIZEOF(n);    //arg = (char *)&n + ((sizeof(n)+3) & ~3);    arg = (char *)&n +4;    for (i = 0; i < n; i++)    {        //sum += va_arg(arg, int);        //sum += *(int *)((arg += _INTSIZEOF(int)) - _INTSIZEOF(int));        //sum += *(int *)(arg+=((sizeof(int)+3) & ~3) - ((sizeof(int)+3) & ~3));        sum += *(int *)(arg+=4 - 4);    }    //va_end(arg);    arg = (char *)0;    return sum / n;}int main(){    int ret = average(3,5,6,4);    printf("ret= %d\n",ret);    system("pause");    return 0;}

代码的功能如下图所示:
这里写图片描述

原创粉丝点击