在c語言變參函式中總是會用到下面幾個巨集:
0、#define _adnbnd (sizeof (acpi_native_int) - 1)
1、#define _bnd(x, bnd) (((sizeof (x)) + (bnd)) & (~(bnd)))
2、#define va_arg(ap, t) (*(t *)(((ap) += (_bnd (t, _aupbnd))) - (_bnd (t,_adnbnd))))
3、#define va_end(ap) (void) 0
4、#define va_start(ap, a) (void) ((ap) = (((char *) &(a)) + (_bnd (a,_aupbnd))))
c語言傳遞引數時是從右到左將引數逐個壓棧,因此c語言裡通過棧指標來訪問引數。c語言在壓引數入棧時是」機器字「的大小為最小單位的,也就是說引數的位址都是」字「對齊的。
1、分析
#define _bnd(x, bnd) :
將該巨集定義展開為如下形式:(
( (sizeof (x)) + (bnd) )
& (
~(bnd) )
)bnd一般取3(32位cpu)或7(64位cpu) 。以32位cpu為例:
~(bnd) = 0xfffffffc,該值相當於乙個掩碼,使任何數與它相與後的結果都是4的倍數,這也正好吻合32位cpu入棧時4位元組對齊的特點;
(sizeof (x)) + (bnd) = sizeof(x) + 3,保證了不管引數x實際佔據幾個位元組,表示式除以4取整後的值總是大於等於引數x的實際大小。
2、分析
#define va_arg(ap, t):
將該巨集定義展開為如下形式:(
*(t *)
( (
(ap) += (_bnd (t, _aupbnd))
) -
( _bnd (t,_adnbnd)
) )
)該巨集的功能是:獲得ap指向引數的值,並使ap指向下乙個引數,t用來指明當前引數型別。
注意((ap) += (_bnd (t, _aupbnd))) 是被一對括號括起來的,然後才減去(_bnd (t, _adnbnd),
所以整個巨集取得的值是ap當前指向的引數值,但是先給ap加了當前引數在字對齊後所佔的位元組數,使其指向了下乙個引數。
3、分析
#define va_end(ap)
(void) 0
可能是為了跟
va_start(ap, a) 成對出現,也有可能是為了保證函式返回時能正確的恢復棧。(有疑問?)
4、分析#define va_start(ap, a)
將該巨集定義展開為如下形式:
(void) (
(ap) =
( (
(char *) &(a)
) +
( _bnd (a,_aupbnd)
) )
)該巨集的功能是:初始化引數指標ap,將函式引數a右邊第乙個可變引數的位址賦給ap。 a必須是乙個引數的指標,所以可變引數型別函式至少要有乙個普通的引數。
C語言(變參函式)
c語言雖然沒有c 的函式過載特性,但也可以實現變參,但要保證第乙個引數資訊的完整性。拓展 定義變參函式時,第乙個引數一般是字串,攜帶後續變參的型別和數量資訊,變參使用三點來表示,如 void sumup const char info,再使用va list va start va arg 和va e...
C語言變參函式實現方法分析
c語言中,最經典的可變引數函式莫過於printf 它的宣告如下所示 int printf const char format,printf 的引數列表中,第1個引數是const char format,而第2個引數是3點 兩者用逗號隔開。這就是可變參函式的宣告方式。那麼,第1個引數和後續的若干引數之...
c語言的變參使用 可變引數巨集 標準預定義巨集
gcc的預處理提供的可變引數巨集定義真是好用 ifdef debug define dbgprint format,args.fprintf stderr,format,args else define dbgprint format,args.endif 如此定義之後,中就可以用dbgprint了...