在學習可變參數時遇到宏
#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
目的是將求出n對齊後的字節數,從這裏來看應該是按照4字節的整數倍來對齊,爲什麼這個宏可以實現4字節的整數倍呢?
首先 (sizeof(n)+sizeof(int)-1) 在 sizeof(int) 時相當於( sizeof(n)+3 ) 如果 用 ( sizeof(n)+3 )/4*4, 則結果爲4字節的整數倍。
所以 ( sizeof(n)+3 )&~(sizeof(int) - 1) 應該相當於 ( sizeof(n)+3 )/4*4, 這是爲什麼呢?
~(sizeof(int) - 1) 就是 ~(4 - 1) = = ~(3) , 二進制 11111100
令x=n/4, y=n%4, 則 n=n/4*4+y, n/4*4是對齊後的字節數,而 m & 11111100剛好將後兩位,即餘數部分置爲了0,保留的剛好是n/4*4部分。
所以
n & ~(sizeof(int) - 1) ) 的作用是去掉n對sizeof(int)的餘數部分
((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) ) 的在作用是對n的字節數按照 sizeof(int) 的整數倍進行對齊(不足需要補充)。
這個宏的設計很巧妙,實際少是用位運算替代了除法操作,從而提高計算效率。
那麼爲什麼要對齊呢?
因爲在函數調用時,參數是通過堆棧進行調用的,估計系統爲了便於管理堆棧和參數,將壓入堆棧的參數的大小進行了固化,其實字節對齊在其他地方也經常使用,如結構體和類的大小等。sizeof() 獲得的僅僅是邏輯長度,並不是真實的物理長度?
另外三個和可變參數相關的宏。
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
v是第一個固定參數, ap 用於指向其他的可變參數, 這裏 ap = (va_list)&v + _INTSIZEOF(v) 使得ap指向第一個固定參數後面的第一個可變參數(壓入堆棧時,先壓入固定參數,再依次壓入可變參數,具體方式和硬件和系統有關),如printf(char *pformat, ....)
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
實現將ap指向的參數取出賦給t,並且讓p指向下一個可變參數 具體是先(ap += _INTSIZEOF(t)) 之後用 (*( t *)(ap-_INTSIZEOF(t))),設計的也很巧
#define va_end(ap) ( ap = (va_list)0 )
最後將ap指針設置爲空。
typedef char * va_list; va_list 就是char *類型的指針。
這些宏在stdarg.h頭文件中。