va_list 模仿学习理解

#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);
    ...

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章