可变参数列表源码剖析及实例解析
来源:互联网 发布: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;}
代码的功能如下图所示:
- 可变参数列表源码剖析及实例解析
- 可变参数列表源码的剖析
- 可变参数列表源码的剖析
- 可变参数列表源码的剖析
- 可变参数列表源码的剖析
- 可变参数列表源码的剖析
- 可变参数列表源码的剖析
- 可变参数列表源码的剖析
- 可变参数列表剖析
- 可变参数列表剖析
- 可变参数列表剖析
- 可变参数列表剖析
- 可变参数列表源码的解析
- 浅析可变参数列表及实例分析
- 可变参数列表解析
- 可变参数列表解析
- 可变参数列表解析
- 可变参数列表解析
- Java常用框架学习
- java List的删除操作
- opendss仿真
- maven学习笔记2
- 位操作的精巧使用
- 可变参数列表源码剖析及实例解析
- 【服务器架构】WEB 前端性能优化
- Linux日常命令
- ambari本地源配置
- 数据结构学习记录-指针与数组
- PowerDesigner 16.5详细安装图解与注册
- 梯形求积公式 和 复合梯形求积公式 Matlab 实现
- (一)线性表、单向链表
- 可变参数列表源码的剖析