#define _vlst (char *)
#define _intsize(n) ((sizeof(n)+sizeof(int)-1)&(~(sizeof(int)-1)))
#define _vastart(ap,v) (ap=_vlst(&v)+_intsize(v))
#define _vaarg(ap,t) (*(t*)((ap+=_intsize(t))-_intsize(t)))
#define _vaend(ap) (ap=(void*)0)
学习宏,看到这些代码,感觉这些很复杂,经过几天努力搞出点儿眉目了.记录备忘备查
#define _intsize(n) ((sizeof(n)+sizeof(int)-1)&(~(sizeof(int)-1)))
1、sizeof(int)-1,因为int一般是4字节,这个式子的值就是3,这里对于二进制来说就是保证最低两位是1;按位取反(~)后,保证了最低两位是0,其他位是1.
2、sizeof(int)-1一般来说是3。
sizeof(n)的值如果是1--4,3加上1--4的数对于二进制来说第三位是1,第三位以上的位是0,保证了跟后面一部分按位与(&)后,除了第三位,其他位都为0.
sizeof(n)的值如果是5--8,3加上5--8的数对于二进制来说第四位是1,第三位及以上的位是0,保证了跟后面一部分按位与(&)后,除了第四位,其他位都为0.
同理,这个宏可以保证整个表达式的值是大于n的4的倍数。
实现了以四的倍数对齐的功能。为后面几个宏的传参打下了基础。
#define _vastart(ap,v) (ap=_vlst(&v)+_intsize(v))
这个相对简单,&v指向了函数的第一个固定参数。_vlst其实就是(char *),把&v转换成字符指针是为了
加上_intsize(v)的时候,指针可以向后移动正确的位置。
指针的向后移动与指针指向的类型所占用的字节数相关。比如int型指针加1,指针会向后移动4个字节。
#define _vaarg(ap,t) (*(t*)((ap+=_intsize(t))-_intsize(t)))
这个宏最为复杂,一定要从括号入手,搞清楚配对关系,才能正确理解。
这个宏实现的功能是,将指针移动指向下一个参数,然后取得当前指针指向的值。具体分析如下:
最内层(ap+=_intsize(t)),是将指针移动指向下一个参数。这时ap的值已经指向下一个参数了,不会变了,这点要注意。
然后((ap+=_intsize(t))-_intsize(t)),地址值又回到当前参数指向位置;
最后(*(t*)((ap+=_intsize(t))-_intsize(t))),(t*)把指针转换成指向t类型的指针,然后
*(t*)((ap+=_intsize(t))-_intsize(t))取得当前参数的值。
因此这个宏可以用类似的方式不断的取到可变参数的值,例如
int a = _vaarg(ap,int);
int b = _vaarg(ap,int);
char c = _vaarg(ap,char);
...