在C中,可變參數用于參數個數,類型不确定的情況,如printf,snprintf函數的實作。
當我們無法列出傳遞函數的所有實參的類型和數目時,可以用省略号指定參數表
void func(...);
void func(parm_list,...);
這是C傳參的一種形式,與固定參數不同。
函數參數的傳遞原理
函數參數以棧的形式存儲,從右往左入棧。
舉個例子:
void func(int x, float y, char z);
在調用函數的時候,實參z先入棧,然後是y,最後是x。在記憶體中變量的存放次序是x->y->z。是以,從理論上來說,隻要知道x,y,z其中一個變量的位址和類型,通過指針運算,可找到其他變量。
typedef char* va_list;
void va_start ( va_list ap, prev_param ); /* ANSI version */
type va_arg ( va_list ap, type );
void va_end ( va_list ap );
va_list是指向目前參數的指針,通過這個指針進行取參。
宏的使用方式如下:
- 先定義一個va_list的變量,假設為ap
- 使用va_start對ap進行初始化,va_start的第一個參數是ap,第二個參數是變參表中“…”前面的那個參數
- 然後調用va_arg擷取參數,第一個參數還是ap,第二個參數是要擷取的參數的類型,并且ap指向下一個變量
- 擷取完參數後,使用va_end關掉ap。va_start和va_end通常成對出現。
例子:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
int my_snprintf(char *dst, int size, char *fmt, ...)
{
int len;
va_list argp;
va_start(argp, fmt);
len = vsnprintf(dst, size, fmt, argp);
len = len > size - 1 ? size - 1 : len;
va_end(argp);
return len;
}
int main(void)
{
char str[8];
int len;
len = my_snprintf(str, sizeof(str), "A:%d:%s", 1, "ABCDEFGH");
printf("str:%s, len:%d\n", str, len);
return 0;
}