printf可變引數原理

2021-08-21 22:18:30 字數 1443 閱讀 2522

當呼叫printf時引數的個數是不限定的,那麼該函式是如何實現的呢?來看一下該函式的定義

int printf(const char *format,[argument]...)
printf的第乙個引數就是那個字元指標即為被雙引號括起來的那一部分,函式通過判斷字串裡控制引數的個數(%d等等)來判斷引數個數及資料型別。例如printf("%d,%d",a,b);彙編**為:

.section 

.data

string out = "%d,%d"

push b

push a

push $out

call printf

注意引數的入棧順序,最後的先壓入棧中,最先的後壓入棧中,引數控制的那個字串常量是最後被壓入的 

該函式的實現涉及到幾個巨集:

c中變長實參標頭檔案stdarg.h提供了乙個資料型別va_list和三個巨集(va_start、va_arg和va_end),用它們在被呼叫函式不知道引數個數和型別時對可變參數列進行測試,從而為訪問可變引數提供了方便且有效的方法。

typedef char * va_list;

#define _intsizeof(n) ((sizeof(n) + sizeof(int) - 1)&~(sizeof(int) - 1))

#define va_start(ap,v) ( ap = (va_list)&v + _intsizeof(v) )

#define va_arg(ap,t) (*(t *)((ap += _intsizeof(t)) - _intsizeof(t)))

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

下面是printf的實現

static char sprint_buf[1024];

int printf(char *fmt, ...)

從上面的**來看,printf似乎並不複雜,它通過乙個巨集va_start把所有的可變引數放到了由args指向的一塊記憶體中,然後再呼叫

vsprintf真正的引數個數以及格式的確定是在vsprintf搞定的。

int vsprintf(char *string, char *format, va_list args)
該函式將args按格式format寫入字串string中,該函式中會用到va_arg來獲取各個引數,正常情況下返回生成字串的長度(除去\0),錯誤情況返回負值

下面是各個巨集的乙個簡單的應用例子,實現乙個多引數的printf

void minprintf(const char *fmt, ...)

switch (*++p)

} va_end(ap);

}

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 可變引數封裝

define fb fmt,fa fmt,va args va args 就只是告訴編譯器,fa可以接受可變引數,不要報錯,相當於又把 傳遞下去了 兩個 的解釋請參見宋寶華 linux裝置驅動程式開發詳解 4.0核心 p80 void fa fmt,typedef char va list va l...

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