C言語の中の変長パラメータ

2795 ワード

私たちはC言語プログラミングにおいて、いくつかのパラメータの個数可変の関数、例えばprintf()に出会います.この関数の定義はこうです. 
int printf( const char* format, ...); 
しかし、長いパラメータの関数はどうやって実現されますか?
このような長いパラメータの関数を実現するには、データ構造va_を使用する必要があります.リストとマクロヴァ_スタートアル、ヴァグend、これらはstdarg.hで定義されたマクロです.
va_リストは、保存関数パラメータを定義したデータ構造である.
va_startマクロはva_を初期化します.list変数の最初のパラメータはva_です.リストオブジェクトは、2番目のパラメータが可変パラメータの前のパラメータであり、固定パラメータです.
初期化が完了しました.list変数を使用すると、va_を使用できます.argマクロ
va_argマクロは後の可変パラメータを得るために使用されます.その最初のパラメータはva_です.リストオブジェクト、2番目のパラメータは戻りパラメータの種類です.
va_endマクロは変数の取得を終了し、そのポインタを変数0にセットします.
次はva_ですリストの具体的な実現(vc 2003):
#ifdef   _M_ALPHA
typedef struct {
         char *a0;        /* pointer to first homed integer argument */
         int offset;      /* byte offset of next parameter */
} va_list;
#else
typedef char *   va_list;
#endif
va_が見られますlistは実際にマシンタイプに関するマクロであり、alphaマシンを除いて、他のマシンタイプはcharタイプのポインタ変数と定義されています.char*と定義されているのは、その変数をアドレス毎に、つまりバイト毎にパラメータを巡回できるからです.マクロの実現は以下の通りで、内容が分かりやすいので、紹介しません.
#define _INTSIZEOF(n)    ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

#define va_start(ap,v)   ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define va_arg(ap,t)     ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap)       ( ap = (va_list)0 )

#ifdef   __cplusplus
#define _ADDRESSOF(v)    ( &reinterpret_cast<const char &>(v) )
#else
#define _ADDRESSOF(v)    ( &(v) )
#endif
参考コードは以下の通りです.
#include <stdio.h>
#include <stdarg.h>
#include <string.h>

void test(char src[], ...);

int main()
{
    char str[] = "content";
    test("this is %d %s %c", 123, str, 'p');
    return 0;
}

void test(char src[], ...)
{
    int num=1;

    va_list args;

    va_start(args, src);

    int i = 1;
    int len = strlen(src);
    while(i<len)
    {
        if(src[i-1] == '%')
        {
            switch(src[i])
            {
                case 'd':
                {
                    int p = va_arg(args, int);
                    printf("%d args :  %d
", num++, p); break; } case 'c': { // ,va_arg int ch = va_arg(args, int); printf("%d args : %c
", num++, (char)ch); break; } case 's': { char * pStr = va_arg(args, char *); printf("%d args : %s
", num++, pStr); break; } } } i++; } va_end(args); }