stdarg.h 中定义可变参数宏

  • va_list 创建参数列表指针 va_list argp;
  • va_start(va_list list_ptr, a1) 初始化指针和定位第一个不定参数 va_start(argp, a1);
  • va_arg(va_list list_ptr, type) 接受列表和类型,返回列表的元素指针 va_arg(argp, int);
  • va_end(va_list list_ptr) 结束可变参数的获取,指针无效化 va_end(argp);
#define _INTSIZEOF(n)   ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )

目的是将求出 n 对齐后的字节数,当 sizeof(n)==4 时,这里按照 4 字节的整数倍来对齐,为什么这个宏可以实现 4 字节的整数倍呢?

首先 (sizeof(n)+sizeof(int)-1)sizeof(int)==4 时相当于 ( sizeof(n)+3 )

+3 保证了 0 的时候还是 3 小于 4 最后还是 0,13 的时候变成 47 最后变成 1,刚好在 4 的 1 倍以上 2 倍以下,再大同理。所以用 (sizeof(n)+3)/4*4, 则结果为 4 字节的整数倍。

所以 ( sizeof(n)+3 )&~(sizeof(int) - 1) 应该相当于 ( sizeof(n)+3 )/4*4, 这是为什么呢?

~(sizeof(int) - 1) 就是 ~(4 - 1) = = ~(3) , 二进制 m & 11111100 刚好将后两位,即余数部分置为了 0,保留的刚好是 n/4*4 部分。

sizeof(n)==8 的情况同理

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

栈区

所以程序运行的过程中总是维护一个充满调用的函数地址和局部变量的巨大的栈,这个内存区域被称为栈区

在一般的程序中,栈区中的栈总是向下生长的,也就是新的元素总是被加载到更低的地址上,这和一般如字符串等常见数据放置的方式不一样,需要注意(下文会有用)

指向原始笔记的链接

参数倒着压栈,栈从高到低生长,v 是第一个,最后放,最低,往上加就变成上一个参数了,所以这个位置就是未知参数的位置,列表开始的位置,刚刚好这个方向上用数组就可以访问到(递增方向,下一个参数的位置,就是高的位置,刚好加就行了)下一个参数

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

由于 +=操作的先后性,这里先移动指针,再算回来原来的位置。因为一开始就是对的,就是第一个。

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

销毁指针

这个设计十分的愚蠢,竟然没有办法给出获取可变参数数量的指导性方法,单纯就是根据数据的存放和指针的移动来得到参数列表里面一堆参数的位置。从而调用参数。