2015年5月4日月曜日

va_list を自前で構築する

C 言語で,可変引数の関数から (与えられた可変引数をそのまま渡して) vprintf を呼ぶのは簡単だけど,そうじゃない場合,例えば何か配列の値を使って vprintf を呼びたいような場合,無の状態から va_list を生成するのが標準の C の範疇では出来ないみたい.

しかたがないので,プラットフォーム依存になるだろうけど,Microsoft VisualC++ (x86) では以下のようにして出来た.
#include <stdio.h>
#include <stdarg.h>

int main( void ){
    va_list vargs;
    
    int args[] = {
        10,
        0, 0,  // double 用領域
    };
    
    *( double *)( &args[ 1 ]) = 1.5;
    
    va_start( vargs, args[ -1 ] );
    vprintf( "hoge %d %f\n", vargs );
    va_end( vargs );
    
    return 0;
}

---- 実行結果 ----
hoge 10 1.5

要は,va_list は普通は CPU のスタック領域に積まれた引数のアドレスを指しているけど,int args[] に無理やりスタックイメージと同じものを作って,va_list でそこを指すようにすれば良い.通常 va_start の第 2引数に渡すのは format 文字列,すなわち %d とかで使う数値が入っているアドレスの 4バイト前なので,ここでも 4バイト前を指すように args[ -1 ] を指定する.
double 型は 8バイトアライメントに配置しなくても良いみたい.
va_end が何をしてるかわからんけど,#define を見る限りなくてもいいみたい.

0 件のコメント:

コメントを投稿