生きる

助けて

C言語で可変長引数を取る関数を定義する

可変長引数とは、printf関数が取るような、あらかじめ個数が決まっていない形式の引数のことである。

例えば、自分用のprintfを新たに定義したいとすると、引数の部分は次のように書く。

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

}

こう書くと、fmtに続く引数が可変になる。 ...の前には引数が複数あってもよいが、...の後に引数があってはならない。 つまり、...は引数の最後でなければならない。

渡された可変長引数を使うには、stdarg.hで定義されている型やマクロを使う。以下にそれらの使い方の例を示す。

#include <stdio.h>
#include <stdarg.h>

void myprintf(char *fmt, ...) {
    va_list ap;
    va_start(ap, fmt);
    
    char *p = fmt;
    
    while (*p) {
        if (*p == 'd') {
            printf("%d ", va_arg(ap, int));
            p++;
            continue;
        }

        if (*p == 'c') {
            printf("%c ", va_arg(ap, char));
            p++;
            continue;
        }
        
        fprintf(stderr, "不正な文字\n");
        exit(1);
    }
    
    printf("\n");
}

va_list型は引数のリストをイテレートするためのポインタを表す。 "va"はおそらく可変超引数を表す英語variadic argumentsの略。

va_start(ap, fmt)によって、apfmtに続く引数のリストの先頭を指している状態になる。 一般にva_startの第二引数には...の直前の引数の識別子を指定する。

引数のリストを順番に調べるには、va_argマクロを使う。va_arg(ap, int)apが指している位置の引数をint型として返し、apが指す位置を一つ先に進める。

myprintf関数は簡易的なprintfを実現する。具体的には、dcからなる文字列と可変長引数を受け取り、可変長引数を参照しながら、dを整数に、cを文字に置き換える。 例えばmyprintf("dcdcd", 1, 'a', 2, 'b', 3)を呼び出すと1 a 2 b 3と表示される。