C言語利用va_list、va_start、va_end、va_argマクロ定義可変パラメータの関数
2207 ワード
可変パラメータの関数を定義する前に、関数パラメータの伝達原理を理解します.
1、関数パラメータはスタックのようなデータ構造でアクセスされ、関数パラメータリストでは右から左に順にスタックに入る.
2、パラメータのメモリ格納フォーマット:パラメータのメモリアドレスはメモリのスタックセグメントに格納され、関数を実行する時、最後の(一番右の)パラメータからスタックに入る.そのためスタックの底の高いアドレス、スタックの上の低いアドレス、例を挙げて説明する:
void test(int a, float b, char c);
では、test関数を呼び出すとき、実参char c先進スタック、それからfloat b、最後にint aとなるので、メモリにおける変数の格納順序はc->b->aである.理念的には、任意の変数のアドレスを検出するだけでなく、他の変数のタイプを知っていて、ポインタシフト演算によって、他の入力変数を見つけることができます.
可変パラメータの関数を実装するには、次のマクロを使用します.
デモの例:標準ライブラリの可変パラメータに関する関数の使用
1、関数パラメータはスタックのようなデータ構造でアクセスされ、関数パラメータリストでは右から左に順にスタックに入る.
2、パラメータのメモリ格納フォーマット:パラメータのメモリアドレスはメモリのスタックセグメントに格納され、関数を実行する時、最後の(一番右の)パラメータからスタックに入る.そのためスタックの底の高いアドレス、スタックの上の低いアドレス、例を挙げて説明する:
void test(int a, float b, char c);
では、test関数を呼び出すとき、実参char c先進スタック、それからfloat b、最後にint aとなるので、メモリにおける変数の格納順序はc->b->aである.理念的には、任意の変数のアドレスを検出するだけでなく、他の変数のタイプを知っていて、ポインタシフト演算によって、他の入力変数を見つけることができます.
可変パラメータの関数を実装するには、次のマクロを使用します.
typedef char* va_list; //
void va_start(va_list ap, prev_param); // , ,
void va_arg(va_list ap, type); // ,
void va_end(va_list ap);// ( NULL)
、デモサンプル:N個の数の和を求めるint sum(int count, ...)
{
int sum = 0;
int i;
va_list ap;
va_start(ap, count);
for (i = 0; i < count; ++i)
{
sum += va_arg(ap, int);
}
va_end(ap);
return sum;
}
int main(int argc, const char * argv[])
{
int ret = sum(5, 1, 2, 3, 4, 5);
printf("sum: %d
",ret);
}
4、 デモの例:標準ライブラリの可変パラメータに関する関数の使用
void test(int count,...)
{
va_list ap;
va_start(ap, count);
vprintf("%d,%d,%d
", ap); //
char buff[1024];
vsprintf(buff, "a=%d,b=%d,c=%d
", ap); //
printf("%s
",buff);
vfprintf(stdout, "a=%d,b=%d,c=%d
", ap); //
// int
vsscanf("10,30,40", "%d,%d,%d", ap); // ,
vsnprintf(buff, 30, "a=%d,b=%d,c=%d", ap); // , (30 )
printf("vsnprintf=%s
",buff);
va_end(ap);
}