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