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

 

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