printf 可變引數封裝

2021-09-24 14:15:04 字數 1547 閱讀 9879

#define fb (fmt, …) fa(fmt, ##__va_args__)     //##__va_args__就只是告訴編譯器,fa可以接受可變引數,不要報錯,相當於又把…傳遞下去了(兩個#的解釋請參見宋寶華《linux裝置驅動程式開發詳解 4.0核心》p80)

void fa(fmt, …)

typedef char *va_list;   //va_list就是個普通的指向char型別的指標而已

#define _intsizeof(n) ( (sizeof(n)+sizeof(int)-1)& ~(sizeof(int)-1) ) //這是獲取某個型別的長度,並按照int長度為邊界對齊,不足4bytes補足,因為棧寬度為4bytes

#define va_start(ap,v) (ap=(va_list)&v + _intsizeof(v)) //這就是使ap指向v的以int長度為邊界的後乙個位置

#define va_arg(ap, type) ( *(type *)((ap+=_intsizeof(type) )-_intsizeof(type)) ) //這其實就是,先使 ap+=_intsizeof(type),跳過下乙個4位元組對齊了的type長度(改變了ap本身的值),然後再返回 ap-_intsizeof(type)位置處的值,是個type型別

#define va_end(ap) (ap=(va_list)0)

void printf(char *fmt, … )    //引數會按照從右向左的順序依次入棧

約定:如果函式引數是帶有…的,那就va_start一套組合拳獲取引數值。如果傳進來的是乙個va_list的值,就省略va_start操作,因為va_start 就是validate va的值,人家都給你傳進來了,你還多此一舉幹嘛。經過分析,乙個…函式沒有辦法再次呼叫…函式,因為沒有辦法通過va_start正確找到 … 的開始位置!

除非使用巨集,如下:

void fa(char *fmt, …)

void fb(char *fmt, …)

int main()

問題:乙個含有…(可變引數)的函式,可不可以將…對應的引數全部傳遞給乙個新的含…(可變引數)的函式?(即乙個…函式可以呼叫另乙個…函式嗎?)

按照…的約定,fb()內部取引數的時候還是使用va_start(va,fmt)來初始化va(而不是使用傳進來的va初始化它。fmt和va確實都指向了有效的地方,但是fb其實是想根據fmt這個指標所佔記憶體的位址、即棧上的位置來拿引數的),所以第二次呼叫va_arg後,其實拿到的東西就不屬於本函式棧裡的內容了,即越界了!

但是joey說可以,將引數格式化輸出到buffer再將buffer傳遞下去。vsprintf()

printf可變引數實現

print.h cpp view plain copy print ifndef print h define print h voidprint char fmt,voidprintch charch voidprintdec intdec voidprintflt doubleflt voidp...

printf可變引數原理

當呼叫printf時引數的個數是不限定的,那麼該函式是如何實現的呢?來看一下該函式的定義 int printf const char format,argument printf的第乙個引數就是那個字元指標即為被雙引號括起來的那一部分,函式通過判斷字串裡控制引數的個數 d等等 來判斷引數個數及資料型...

C可變引數 printf(巨集處理可變引數)

x86平台下的巨集定義 typedef char va list 記憶體對齊 與sizeof int 對齊 0 sizeof n 4,intsizeof n 4 4 sizeof n 8,intsizeof n 8 define intsizeof n sizeof n sizeof int 1 s...