可變引數函式 以printf為例子

2021-07-25 07:56:14 字數 2258 閱讀 8838

void foo(int argv1, char argv2, …)

在參數列的末尾給出省略號,表明這個函式的引數是可變的

程序在呼叫函式時,會將函式引數壓入使用者棧,壓入的順序是從參數列右端開始,從右至左的壓棧順序支援了可變引數的實現。左邊的引數在低位址,右邊的引數在高位址。進入函式後,以左邊的引數為線索,可透過指標依次訪問右邊省略掉的引數。

可變引數的實現一定會涉及到三個函式和乙個變數,巨集定義在stdarg.h中

void va_start(va_list ap, last);

type va_arg(va_list ap, type);

void va_end(va_list ap);

實現正確的函式呼叫,可遵循以下步驟:

1.定義乙個va_list型別變數,變數名為ap

2.使用函式va_start(ap, last)對ap進行初始化,第乙個引數是ap,第二個引數是省略號前乙個變數,在有多個變數的情況下需注意。

3.使用va_arg(ap, type)獲取省略號中的可變引數,該可變引數的型別應為type,並將指標指向下乙個可變引數

4.在獲取完所有的可變引數後(需要小心指標越界),用函式va_end(ap)關閉ap。

下面是glibc中函式printf()的實現原始碼

//glibc 2.14.1

/* write formatted output to stdout from the format string format. */

/* varargs1 */

int__printf (const

char *format, ...)

我們可以自己實現簡易版的myprintf()

#include 

#include

//如果在嵌入式系統中,putchar(ch) 可換成串列埠輸出函式

#define console_print(ch) putchar(ch)

void myprintf(char* fmt, ...);

void printch(char ch);

void printdec(int dec);

void printflt(double flt);

void printbin(int bin);

void printhex(int hex);

void printstr(char* str);

int main(void)

void myprintf(char* fmt, ...)

pfmt++;

}else

}va_end(vp);

}void printch(char ch)

void printdec(int dec)

printdec(dec/10);

printch( (char)(dec%10 + '0'));

}void printflt(double flt)

void printstr(char* str)

}void printbin(int bin)

printbin(bin/2);

printch( (char)(bin%2 + '0'));

}void printhex(int hex)

printhex(hex/16);

if(hex < 10)

else

}

1.可變引數』…』裡面的char會被提公升為int,float會被提公升為double。如果我們將va_arg(ap, int)改為va_arg(ap, char),系統會給出乙個警告。詳情可見[3].

waring: 'char' is promoted to 'int' when passed to through '...'
2.一定要使用arg_end(),可提高程式的移植性和健壯性。詳情可見[4].

【reference】

1.myprintf實現

2.stdarg相關函式

3.va_arg不可接受的型別

4.va_end是必須的嗎

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等等 來判斷引數個數及資料型...

printf 可變引數封裝

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