[Atelier Blue アトリエブルー]HomeMemo>C言語での可変個の引数

C言語での可変個の引数

C言語で可変個の引数を使うときには「stdarg.h」のマクロを使うと思います。x86系CPUでは普通変数をスタックに積んで関数を呼び出します(高速な呼び出しのためにレジスタで行う場合もあります)。つまりx86系CPUを対象としたこのマクロでやっていることはポインタ演算になるわけです。

謝辞

ボーランドとマイクロソフトのヘッダとライブラリに感謝します。

中身

まずはこのヘッダの中身を知らなければいけません。

詳細はこちら(別のサイトに飛びます)

引数のサイズを知る

アドレス演算をするためにはそれぞれの型のサイズを知る必要があります。そして、ソースコードを読む限り引数のサイズはintのサイズ以上なのです。というわけで以下のようなマクロを先に定義しておきます。

#define __va_size(x)  ((sizeof(x) + sizeof(int) - 1) & ~(sizeof(int) - 1)) 

いわゆる切り上げをやっています。

void va_start(va_list ap, last);

「last」では最後の引数を取ります。

#define va_start(ap,last) (ap = (va_list)((char *)(&last) + __va_size(last)))

自分のスタックアドレスに自分のサイズを足して次の値を取り出せるようにしています。

type va_arg(va_list ap, type);

今度は値の取り出しです。

#define va_arg(ap, type) (*(type *)((ap += __va_size(type)) - (__va_size(type))))

こんな感じです。

void va_end(va_list ap);

コレは一番簡単です。

#define va_end(ap) ((void)0)

void va_copy(va_list dest, va_list src);

本当に申し訳ないんですが、手元のヘッダファイルにはコレが載っていませんでした。まあ、上の三つで代用できるので今回はパスです。

その他

とりあえず上のをまとめたものに色々足します。

/* 標準ライブラリ(stdarg.h)*/

/* 可変個の引数をサポートをする。 ver1.0 作成者(auther):利都(Rito) 作成日(make):2006-4-15
    http://www.atelier-blue.com/ mail:webmaster@atelier-blue.com */

#ifndef __INC_STDARG_H
#define __INC_STDARG_H

typedef char * va_list;

#define __va_size(x)  ((sizeof(x) + sizeof(int) - 1) & ~(sizeof(int) - 1))

#define va_start(ap,last) (ap = (va_list)((char *)(&last) + __va_size(last)))
#define va_arg(ap, type) (*(type *)((ap += __va_size(type)) - (__va_size(type))))
#define va_end(ap) ((void)0)

#endif 

あなたの環境で動くかは保証できませんが、興味のある方は試してみてください。下がテスト用のソースコードです(本当はもっと色々な引数で試してみないといけませんね)。

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



/* 標準ライブラリ(stdarg-t.h)*/

/* 可変個の引数をサポートをする「stdarg」のテスト用ヘッダ。 ver1.0 作成者(auther):利都(Rito)
    作成日(make):2006-4-15 http://www.atelier-blue.com/ mail:webmaster@atelier-blue.com
    */



#ifndef __INC_STDARG_H
#define __INC_STDARG_H

typedef char * va_list_t;

#define __va_size(x)  ((sizeof(x) + sizeof(int) - 1) & ~(sizeof(int) - 1))

#define va_start_t(ap,last) (ap = (va_list)((char *)(&last) + __va_size(last)))
#define va_arg_t(ap, type) (*(type *)((ap += __va_size(type)) - (__va_size(type))))
#define va_end_t(ap) ((void)0)

#endif //コンパイラのものを利用する
void test1(int count,...){
    va_list args;
    int i;

    va_start(args,count);

    for(i=0;i<count;i++){
        printf("%2d:%d\n",i,va_arg(args,int));
    }
    va_end(args);
}
//自分で作ったものを利用する
void test2(int count,...){
    va_list_t args;
    int i;

    va_start_t(args,count);

    for(i=0;i<count;i++){
        printf("%2d:%d\n",i,va_arg_t(args,int));
    }
    va_end_t(args);
}

int main(){
    test1(10,1,2,3,4,5,6,7,8,9,10);
    test2(10,1,2,3,4,5,6,7,8,9,10);
    return 0;
}



ページの一番上へ
初版2006-4-16 最終更新2006-11-19
[Atelier Blue アトリエブルー]HomeMemo>C言語での可変個の引数