c語言中關於變長引數函式的原理
printf函式是在串列埠資訊列印中和串列埠命令列介面功能實現中經常用的函式。呼叫方式一般是這樣子的printf("cmd =%s\r\rn", cmd_str),printf("vol=%dmV, current=%dmA.", vol,current)等方式。在字串後面的輸入的引數個數可變化,printf的這種引數就是變長引數。
變長引數的函式實現需要使用strarg.h標頭檔案中定義的一個重要的巨集,如下
typedef char *va_list
void va_start(va_list )
void va_end(va_list ap);
下面編寫一個變長引數的函式來說明其原理。
void print_demo(char *form,...) { va_list argp; int argno = 0; int para; /*argps獲取輸入第二個引數的指標*/ va_start(argp, form); while(1) { /*按4位元組字的方式取得輸入變長引數的數值 para分別返回main函式中呼叫傳入的字串指標,a,b,c三個變數的值*/ para = va_arg(argp, int); argno++; /*這個迴圈中要根據輸入的form中把指向的字串中的資料的個數進行退出*/ if(argon > 4) { break; } } va_end(argp); } int main(void) { unsigned char a = 1, b = 2, c = 3; char *ss = "hello"; printf_demo("%s,%d,%d,%d,%s", s, a, b, c, s); }
下面是程式模擬執行的結果:
在函式print_demo中的每個迴圈打印出來一個輸入引數的值,即分別打印出來print_demo()函式中輸入的字串s的地址,a的值,b的值,c的值,字串s的地址。
總結一下變長引數的實現原理,main函式中執行printf_demo("%s, %d,%d,%d,%s", s, a, b, c, s)時,程式第一個引數格式化字串的指標賦值到暫存器R0, 第二個引數s賦值到暫存器R1, 第三個引數a賦值到暫存器R2, 第四個引數b賦值到暫存器R3,第五個引數c, 第六個引數s壓入堆疊。
執行到printf_demo內部時,R0-R3壓入堆疊中去,此時堆疊中儲存了第一個引數格式化字型串指標,s,a,b,c,s這個五個數值。va_start(argp, form);這個語句讀取到堆疊中的第二個引數的在記憶體中的指標。para = va_arg(argp, int);這個函式迴圈呼叫 取出來第二個引數到第五個引數的值。