掲示板利用宣言

 次のフォームをすべてチェックしてからご利用ください。

 私は

 題名と投稿者名は具体的に書きます。
 課題の丸投げはしません。
 ソースの添付は「HTML変換ツール」で字下げします。
 返信の引用は最小限にします。
 環境(OSとコンパイラ)や症状は具体的に詳しく書きます。
 返信の付いた投稿は削除しません。
 マルチポスト(多重投稿)はしません。

掲示板2

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.23686

動的引数の printf
投稿者---しーまま(2005/10/18 15:54:56)


引数の個数やタイプが動的に指定される場合の、メモリへの書式付出力の方法を教えてください。

例えば、
pfmt 書式文字列へのポインタ
var0 文字列ポインタ
var1 整数
var2 実数
pmem 出力先のポインタ
のとき、どのようにコーディングすれば良いのでしょうか?

書式文字列と各変数(varx)との整合性はとれていて、出力先のメモリ領域も十分であると仮定します。

どうぞよろしくお願いします。




この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:動的引数の printf 23689 RiSK 2005/10/18 16:08:10
<子記事> Re:動的引数の printf 23690 Blue 2005/10/18 16:11:31
<子記事> Re:動的引数の printf 23716 しーまま 2005/10/19 08:19:35
<子記事> Re:動的引数の printf 23735 しーまま 2005/10/20 03:17:15
<子記事> Re:動的引数の printf 23778 円零 2005/10/21 18:58:16
<子記事> Re:動的引数の printf 23783 しーまま 2005/10/22 02:13:06


No.23689

Re:動的引数の printf
投稿者---RiSK(2005/10/18 16:08:10)


>引数の個数やタイプが動的に指定される場合の、メモリへの書式付出力の方法を教えてください。

質問がよく分かりませんが,
sprintf, vsprintfではダメなのでしょうか?


この投稿にコメントする

削除パスワード

No.23690

Re:動的引数の printf
投稿者---Blue(2005/10/18 16:11:31)


ものすごく意味不明です。
printfでやりたいのでしょうか?

> メモリへの書式付出力の方法
のメモリとは?

□環境(OSとコンパイラ)や症状は具体的に詳しく書きます。
にチェックを入れて質問をしたのではないのでしょうか?


この投稿にコメントする

削除パスワード

No.23702

Re:動的引数の printf
投稿者---si(2005/10/18 19:10:44)


多分 sprintf したいんじゃないのかな?


この投稿にコメントする

削除パスワード

No.23716

Re:動的引数の printf
投稿者---しーまま(2005/10/19 08:19:35)


説明が不十分のようでした。(スミマセン)

例えば、
-------------------------------
int func(char *pfmt)
{
char *ptext="hello world";
int i=123;
float f=0.5f;
void *var0 = (void *)ptext;
void *var1 = (void *)(&i);
void *var2 = (void *)(&f);
void *var3 = NULL;
char *pmem = new char[1024];// 出力先のポインタ

// ???

int ret = printf("%s", pmem);

delete [] pmem;

return ret;
}

int main()
{
func("%s %d %f");
func("%s %d");
}
-------------------------------
のとき、???の部分は、どのようにコーディングすれば良いのでしょうか?
なお、VC++6.0です。

※funcへの引数である書式は動的に決定されます。また、詳細は省略しましたが、varxの内容も動的に決定されます。


この投稿にコメントする

削除パスワード

No.23718

Re:動的引数の printf
投稿者---まきじ(2005/10/19 08:44:29)


>float f=0.5f;
>void *var0 = (void *)ptext;
>void *var1 = (void *)(&i);
>void *var2 = (void *)(&f);
>void *var3 = NULL;
>char *pmem = new char[1024];// 出力先のポインタ
>int ret = printf("%s", pmem);

sprintf(pmem,pfmt,var0,*var1,*var2) としたいところですが
pfmt の内容が "%%s" や "%%s %%d" や "%%s %%d %%f"
と変化するから、この方法では無理かな。

var0 var1 var2 var3 を func の可変長引数とした方を良いと思います。
でも可変長引数だと全て同じ型でない駄目ですね。


この投稿にコメントする

削除パスワード

No.23719

Re:動的引数の printf
投稿者---nop(2005/10/19 08:58:05)


>???の部分は、どのようにコーディングすれば良いのでしょうか?

まず、???の箇所で何をやりたいのでしょうか?
日本語で説明して下さい。

そもそも、日本語で説明できない処理を、
どの様にしてコンピュータに処理させるのか、
判らなくて当然です。

まず、コーディング内容を考える前に、
「何をしたいのか」「何をするべきなのか」を、
日本語で整理してみましょう。


この投稿にコメントする

削除パスワード

No.23732

Re:動的引数の printf
投稿者---しーまま(2005/10/20 01:49:15)


説明が不十分のようでした、申し訳ございません。
ただ、前後のコードから推測いただけると思ったものですから・・・。

>日本語で説明して下さい。

varx などはタイプや個数が「動的」に変わります。また書式文字列も、これら varx に整合性がある内容で、「動的」に変わります。


この投稿にコメントする

削除パスワード

No.23734

Re:動的引数の printf
投稿者---かずま(2005/10/20 02:34:52)


> 説明が不十分のようでした、申し訳ございません。
> ただ、前後のコードから推測いただけると思ったものですから・・・。

この推測はあたっていますか?
#include <stdio.h>
#include <stdarg.h>

int func(char *pfmt, ...)
{
    int ret;
    char *pmem = new char[1024];
    va_list ap;
    va_start(ap, pfmt);
    ret = vsprintf(pmem, pfmt, ap);
    va_end(ap);
    printf("%s\n", pmem);
    delete[] pmem;
    return ret;
}

int main(void)
{
    char *ptext = "hello world";
    int i = 123;
    float f = 0.5f;

    func("%s %d %f", ptext, i, f);
    func("%s %d", ptext, i);
    return 0;
}
new や delete を使っているから C++ ですね。
それから、投稿するときは、【掲示板利用宣言】を守ってください。


この投稿にコメントする

削除パスワード

No.23720

Re:動的引数の printf
投稿者---まきじ(2005/10/19 09:06:31)


ある型一つに対して変数が一つとすれば、表示/非表示のフラグを
用意して以下の様に作ってみました。

#include<stdio.h>
void func(int i, int f, int s){

    int x = 10;
    float y = 10.5;
    char *str = "hoge";
    char buf[128]={'\0'};
    
    if(i) sprintf(buf,"%d",x);
    if(f) sprintf(buf,"%s %f",buf,y);
    if(s) sprintf(buf,"%s %s",buf,str);
    
    if(buf[0] != '\0') printf("%s\n",buf);
}
int main(void){

    int i = 1;
    int f = 0;
    int s = 1;
    
    func(i, f, s);
    
    return 0;
}



この投稿にコメントする

削除パスワード

No.23721

Re:動的引数の printf
投稿者---しーまま(2005/10/19 11:04:44)


わざわざコードまで書いていただき、
ありがとうございました。

前の投稿ではバリエーションの一例を示してあるだけで、
実際はもっと沢山あります。

ので、条件で切り分ける、というアプローチではできません。

スタックをいじくる関数を使うはずです。
それが判らないのですが・・・。

いずれにしても、ありがとうございました。


>ある型一つに対して変数が一つとすれば、表示/非表示のフラグを
>用意して以下の様に作ってみました。
>
><pre>#include<stdio.h>
void func(int i, int f, int s){

int x = 10;
float y = 10.5;
char *str = "hoge";
char buf[128]={'\0'};

if(i) sprintf(buf,"%d",x);
if(f) sprintf(buf,"%s %f",buf,y);
if(s) sprintf(buf,"%s %s",buf,str);

if(buf[0] != '\0') printf("%s\n",buf);
}
int main(void){

int i = 1;
int f = 0;
int s = 1;

func(i, f, s);

return 0;
}</pre>



この投稿にコメントする

削除パスワード

No.23722

Re:動的引数の printf
投稿者---ぽこ(2005/10/19 13:03:32)


他の方々が往々に口にしていますが、vsprintf()やsprintf()との
違い/使用できない理由をまず説明していただけませんか?
また、細かい仕様を説明できないのであれば、使用例/その結果を
説明していただけると理解の助けになると思います。


この投稿にコメントする

削除パスワード

No.23733

Re:動的引数の printf
投稿者---しーまま(2005/10/20 02:14:30)


>ある型一つに対して変数が一つとすれば、表示/非表示のフラグを
>用意して以下の様に作ってみました。

ありがとうございます。

この線かもしれないのですが、ただ、書式文字列は「動的」なので・・・。
例えば、実行時にユーザーが入力する、など。


この投稿にコメントする

削除パスワード

No.23736

Re:動的引数の printf
投稿者---まきじ(2005/10/20 08:08:57)


>この線かもしれないのですが、ただ、書式文字列は「動的」なので・・・。

だからフラグを立てて、1 の変数だけ連結してます。

>例えば、実行時にユーザーが入力する、など。

"%d %s %f" と入力させるのですか?
それは良くないかと・・


この投稿にコメントする

削除パスワード

No.23723

ご期待にそえるかわかりませんが
投稿者---だん(2005/10/19 13:07:21)


突然のレス失礼します
いつもお世話になっております。

私は組み込み業界で働いています。
それで、このスレッドを見たときに
・引数を動的に指定する(引数の個数も)
・フォーマット関数の出力先を任意なものにしたい
と理解してこのレスを書いています。
例としては、
フォーマット関数の出力先を
RAM(通常であればsprintfです)だったり
LCDだったり、いろいろな出力先が考えられます。
私は以下のようにして実装しました。

#include <stdarg.h>

typedef void (*FUNC_PUT)(char);

va_list Ap;

// RAMにフォーマット関数の結果を出力する
dan_str_printf(unsigned long addr,char *format_str, ...)
{
addrを使い出力先アドレスを指定
va_start(Ap,format_str);
dan_format_write(format_str,dan_str_put)
va_end(Ap);
}

// RAMに1文字出力する
void dan_str_put(char dat)
{
RAMに1文字出力する処理
}

// LCDにフォーマット関数の結果を出力する
dan_lcd_printf(unsigned long addr,char *format_str, ...)
{
addrを使い出力先アドレスを指定
va_start(Ap,format_str);
dan_format_write(format_str,dan_lcd_put)
va_end(Ap);
}

// LCDに1文字出力する
void dan_lcd_put(char dat)
{
LCDに1文字出力する処理
}

// 書式解析関数
void dan_format_write(char *format_str,FUNC_PUT exec)
{
va_arg(Ap,???);を使い
%の書式指定を<stdio.h>のsprintfを使うか
自作するなどして書式解析
第二引数の関数を用いて出力
}

参考になればと思います



この投稿にコメントする

削除パスワード

No.23735

Re:動的引数の printf
投稿者---しーまま(2005/10/20 03:17:15)


みなさま、ありがとうございます。
どうも私の説明が「雑」のようでした。申し訳ございませんでした。

さて、vprintf() 系の関数は、
void foo(char *p, ...)
といったユーザー定義の動的引数関数の中で使うものと認識しております。
(そもそもこの認識に誤りがあるかもしれませんが)

そして、foo() は、
foo("%d %s", a, b);
というように「静的」にコーディングされます。

これを「動的」にコーディングできないか、というのが目論見です。

だんさんのコメントに「書式解析」という言葉がありましたが、
もしかすると、この線かもしれません。ただ、もうちょっと簡単にできる方法が
あったように記憶しております。
(ちょっと怪しいですが)

再度、サンプルコードを提示させていただきます。
(前回のサンプルコードは不正確のようでした)

ヒントでもなんでも結構です。
どうぞよろしくお願いいたします。

////////////////////////////////////////////////////////////
//
//

enum TP { TPINT, TPSTR, TPFLT };

void *_pvar[1024];
TP _type[1024]; // これは不要かもしれません
char *_pfmt = NULL;

////////////////////////////////////////////////////////////
//
// この関数で、_pvar、_type、および _pfmt に値が代入されます。
//
// 下記のコーディングでは、変数は3個ですが、
// 実際には、実行時にユーザーが指定しますので、
// 何個になるかは未定です。また、タイプも同様に未定です。
//
// ただし、変数の個数、タイプ、および書式文字列の内容は
// 整合性があるものとします。
//
void black_box(void)
{
    // 説明のため、あえて開放はしません
    //
    int *pi = new int;
    char *ps = new char[256];
    float *pf = new float;

    *pi = 123;
    strcpy(ps, "hello world");
    *pf = 0.5f;

    _pvar[0] = (void *)pi;
    _pvar[1] = (void *)ps;
    _pvar[2] = (void *)pf;
    _type[0] = TPINT;
    _type[1] = TPSTR;
    _type[2] = TPFLT;
    _pfmt = "%d %s %f";
}

int dprintf(char *pfmt)
{
    char *pbuff = new char[256];

       ... // pfmt に従い、_pvar が指し示すエリアの内容を pbuff に出力する


    int ret = printf("%s", pbuff);
    delete [] pbuff;

    return ret;
}

int main()
{
    black_box();

    int ret = dprintf(_pfmt);

    return ret;
}











この投稿にコメントする

削除パスワード

No.23737

Re:動的引数の printf
投稿者---nop(2005/10/20 09:43:25)


>というように「静的」にコーディングされます。
>これを「動的」にコーディングできないか、というのが目論見です。

コーディング自体は常に静的なものですが?
やりたい事が全く持って見えてきません。

・書式文字列と引数は「誰が」「どの様に」入力するのか?
・書式文字列と引数は「どの様に」関数に渡したいのか?

など、あなたの説明には重要な要素が欠けています。
そもそも、他人に日本語で正確に説明出来ない事を、
どの様にしてコンピュータに伝えれば良いか判らないのは当然の事です。

・データ構造
・入力
・出力

を整理して、日本語で説明出来る様にして下さい。

# 要するに抽象的過ぎます。


この投稿にコメントする

削除パスワード

No.23741

Re:動的引数の printf
投稿者---しーまま(2005/10/20 13:39:10)


重ね重ねすみません。

No.23735 のソースコードをちょっと変更した抜粋です。関数の使い方は適当ですが、意図は伝わると思います。
どうぞよろしくお願いいたします。

enum TP { TPINT, TPSTR, TPFLT };

void *_pvar[1024];
TP _type[1024]; // これは不要かもしれません
char *_pfmt = NULL;

int get_type_and_data(TP *ptype, void **ppvar)
{
    int ret = 1;

    printf("TYPE ?");

    char ctype = getch();
    if( ctype == 'I' )
    {
        *ptype = TPINT;
        printf("VALUE ?");
        *ppvar = new int;
        **ppvar = atoi(get_input_string());
    }
    else if( ctype == 'S' )
    {
        *ptype = TPSTR;
        printf("VALUE ?");
        **ppvar = new char[1024];
        strcpy(*ppvar = get_input_string());
    }
    else if( ctype == 'F' )
    {
        *ptype = TPFLT;
        printf("VALUE ?");
        *ppvar = new float;
        **ppvar = atof(get_input_string());
    }
    else
    {
        ret = 0;
    }

    return ret;
}

void add_type_and_data_to_buffer(TP type, char *pvar)
{
    // _type と_pvar に追加
}

void set_format_string(char *pfmt)
{
    // _pfmt にコピー
}

int black_box(void)
{
    TP type;
    void *pvar;
    char *pfmt;

    int ret = 1;
    while( ret )
    {
        ret = get_type_and_data(&type, &pvar);
        if( ret )
        {
            add_type_and_data_to_buffer(type, pvar);
            free pvar;
        }
    }

    ret = get_format_string(&pfmt);
    if( ret )
    {
        set_format_string(pfmt);
    }

    return ret;
}



>>というように「静的」にコーディングされます。
>>これを「動的」にコーディングできないか、というのが目論見です。
>
>コーディング自体は常に静的なものですが?
>やりたい事が全く持って見えてきません。
>
>・書式文字列と引数は「誰が」「どの様に」入力するのか?
>・書式文字列と引数は「どの様に」関数に渡したいのか?
>
>など、あなたの説明には重要な要素が欠けています。
>そもそも、他人に日本語で正確に説明出来ない事を、
>どの様にしてコンピュータに伝えれば良いか判らないのは当然の事です。
>
>・データ構造
>・入力
>・出力
>
>を整理して、日本語で説明出来る様にして下さい。
>
># 要するに抽象的過ぎます。



この投稿にコメントする

削除パスワード

No.23742

Re:動的引数の printf
投稿者---nop(2005/10/20 14:02:36)


>関数の使い方は適当ですが、意図は伝わると思います。

私が書いた日本語の文章の意図が、あなたに伝わっていないのに、
あなたが書いたCの文章の意図が、私に伝わるとお思いなのですか?

いちいちCソースを考えて書いている暇があるのでしたら、
まずは、日本語で要求仕様をまとめて下さい。
もちろん、その文章で他人に仕事として任せられるほど詳細に。



この投稿にコメントする

削除パスワード

No.23738

Re:動的引数の printf
投稿者---かずま(2005/10/20 10:09:16)


>   ... // pfmt に従い、_pvar が指し示すエリアの内容を pbuff に出力する

int dprintf(char *pfmt)
{
    char *pbuff = new char[256];
    char *p = pbuff;

    for (int i = 0; *pfmt; pfmt++)
        if (*pfmt == '%')
            switch (*++pfmt) {
            case 'd': p += sprintf(p, "%d", *(int *)_pvar[i++]); break;
            case 's': p += sprintf(p, "%s", (char *)_pvar[i++]); break;
            case 'f': p += sprintf(p, "%f", *(float *)_pvar[i++]); break;
            }
        else
            *p++ = *pfmt;
    *p = '\0';

    int ret = printf("%s", pbuff);
    delete [] pbuff;

    return ret;
}



この投稿にコメントする

削除パスワード

No.23739

Re:動的引数の printf
投稿者---しーまま(2005/10/20 13:12:38)


ありがとうございます。

やはり、書式文字列の解析しかないのでしょうか?
うーん。

> ... // pfmt に従い、_pvar が指し示すエリアの内容を pbuff に出力する

case 'd': p += sprintf(p, "%d", *(int *)_pvar[i++]); break;
case 's': p += sprintf(p, "%s", (char *)_pvar[i++]); break;
case 'f': p += sprintf(p, "%f", *(float *)_pvar[i++]); break;



この投稿にコメントする

削除パスワード

No.23746

またまたご期待にそえるかわかりませんが
投稿者---だん(2005/10/20 14:22:05)


// 前回の自分の書いたレス読みました?
// 書式解析は自分でやってもいいのですが、
// sprintfを使えば、解析する必要はほとんどないのです。
// 以前、私が作ったソースをちょっぴり改造してみましたのでレスします
// ワイド文字とfloat型,double型には対応していませんが
// 以下でほとんど機能するはずです。

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


// 動的な書式に対応したsprintf
void dynamic_sprintf(char *buffer,char *format, ...)
{
    va_list ap;
    unsigned long esc_flag = 0;
    char esc_msg[32];
    char *esc_msg_ptr;
    unsigned long val;

    va_start(ap,format);
    while(1){
        if(*format == '\0') break;
        if(*format == '%'){
            esc_msg_ptr = esc_msg;
            *esc_msg_ptr++ = *format++;
            while(1){
                if(*format == 'd') break;
                if(*format == 'i') break;
                if(*format == 'o') break;
                if(*format == 'u') break;
                if(*format == 'x') break;
                if(*format == 'X') break;
                if(*format == 's') break;
                if(*format == 'S') break;
                if(*format == '%') break;
                *esc_msg_ptr++ = *format++;
            }
            *esc_msg_ptr++ = *format++;
            *esc_msg_ptr = '\0';
            val = va_arg(ap,unsigned long);
            buffer = buffer + sprintf(buffer,(const char *)esc_msg,val);
        }else *buffer++ = *format++;
    }
    *buffer = '\0';
    va_end(ap);
}





この投稿にコメントする

削除パスワード

No.23747

一応、使い方を...
投稿者---だん(2005/10/20 14:42:29)


// 一応、使い方を...

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


// 動的な書式に対応したsprintf
void dynamic_sprintf(char *buffer,char *format, ...)
{
    va_list ap;
    unsigned long esc_flag = 0;
    char esc_msg[32];
    char *esc_msg_ptr;
    unsigned long val;

    va_start(ap,format);
    while(1){
        if(*format == '\0') break;
        if(*format == '%'){
            esc_msg_ptr = esc_msg;
            *esc_msg_ptr++ = *format++;
            while(1){
                if(*format == 'd') break;
                if(*format == 'i') break;
                if(*format == 'o') break;
                if(*format == 'u') break;
                if(*format == 'x') break;
                if(*format == 'X') break;
                if(*format == 's') break;
                if(*format == 'S') break;
                if(*format == '%') break;
                *esc_msg_ptr++ = *format++;
            }
            *esc_msg_ptr++ = *format++;
            *esc_msg_ptr = '\0';
            val = va_arg(ap,unsigned long);
            buffer = buffer + sprintf(buffer,(const char *)esc_msg,val);
        }else *buffer++ = *format++;
    }
    *buffer = '\0';
    va_end(ap);
}


void main(void)
{
    char a[1024];
    unsigned char uc08_a;
    unsigned short uc16_a;
    unsigned long uc32_a;

    uc08_a = 0x11;
    uc16_a = 0x2233;
    uc32_a = 0x44556677;

    // この場合,aは"11223344556677"になる
    dynamic_sprintf(a,"%x%x%x",uc08_a,uc16_a,uc32_a);

    // この場合,aは"112233"になる
    dynamic_sprintf(a,"%x%x",uc08_a,uc16_a);
}
// この考え方であってます?



この投稿にコメントする

削除パスワード

No.23756

Re:一応、使い方を...
投稿者---しーまま(2005/10/20 17:59:34)


ありがとうございます。

だんさんの main() では、dynamic_sprintf() への引数が、2個の場合と3個の場合とが「静的」にコーディングされています。

一方、No.23741 の black_box() はユーザーからの入力を得る関数ですが、引数の個数は「実行時にしか」わかりません。

もちろん、sprintf() を使うやり方は、わかります。要は、書式文字列の%??の部分のみ逐次分離し、個別に sprintf() に食わせる、結果を文字列バッファに追加してゆく、ということだと思います。

だんさんは、void dynamic_sprintf(char *buffer,char *format, ...)
といった「動的引数のユーザー定義の関数」を使用されていますが、私の記憶が正しければ、「動的引数のユーザー定義の関数」は一切使用せずに、できたはずです。


>// 一応、使い方を...

void main(void)
{
    char a[1024];
    unsigned char uc08_a;
    unsigned short uc16_a;
    unsigned long uc32_a;

    uc08_a = 0x11;
    uc16_a = 0x2233;
    uc32_a = 0x44556677;

    // この場合,aは"11223344556677"になる
    dynamic_sprintf(a,"%x%x%x",uc08_a,uc16_a,uc32_a);

    // この場合,aは"112233"になる
    dynamic_sprintf(a,"%x%x",uc08_a,uc16_a);
}
// この考え方であってます?




この投稿にコメントする

削除パスワード

No.23751

Re:動的に引数の個数、型が変化する printf
投稿者---si(2005/10/20 15:27:32)


>やはり、書式文字列の解析しかないのでしょうか?
>うーん。
解析したくなければ、解析する必要が無い形で出力関数へ引数を渡せば良いじゃないですか

enum arg_id { NUM_INT,NUM_FLOAT,STR_A,STR_J };
struct arg_t {
  int id;
  union {
   int inum;
   float fnum;
   char *str;
  } body;
};
int func(char *fmt,int argc,struct arg_t argv[]);

#大いなる疑問(多分みなさんと同じだと思いますが)
#やりたいことは、sprintf/vsprintf だとしか思えない
#何故、これが使えないのか
#どういった仕様なのか、良く分からん?


この投稿にコメントする

削除パスワード

No.23757

Re:動的に引数の個数、型が変化する printf
投稿者---しーまま(2005/10/20 18:06:54)


お手数をおかけしております。

おっしゃるとおり、できる方法はあります。
例えば、No.23746 のだんさんの void dynamic_sprintf(char *buffer,char *format, ...) です。

ただ、この方法でも書式文字列の解析は行っているわけで、
別のレスでも述べましたが、解析を全く行わずにできたはずです。

どこかにソースコードがあるはずです。
再度、ウェブでじっくり検索してみます。

ありがとうございました。


>#大いなる疑問(多分みなさんと同じだと思いますが)
>#やりたいことは、sprintf/vsprintf だとしか思えない
>#何故、これが使えないのか
>#どういった仕様なのか、良く分からん?




この投稿にコメントする

削除パスワード

No.23760

Re:動的に引数の個数、型が変化する printf
投稿者---かずま(2005/10/20 22:05:33)


> 別のレスでも述べましたが、解析を全く行わずにできたはずです。

解析を全く行わないプログラムです。
#include <iostream>
#include <sstream>
#include <string>
#include <list>

struct Print {
    virtual void print(std::ostream &o) = 0;
};

template<class T> class black_box : public Print {
    T val;
public:
    black_box(T x) : val(x) { }
    void print(std::ostream &o) { o << val; }
};


void dprintf(std::list<Print *> &pfmt)
{
    std::list<Print *>::iterator it = pfmt.begin();
    if (it == pfmt.end()) return;
    std::ostringstream oss;
    (*it)->print(oss);
    while (++it != pfmt.end()) (*it)->print(oss << ' ');
    std::cout << oss.str() << '\n';
}

int main()
{
    black_box<int>          var0 = 123;
    black_box<const char *> var1 = "hello world";
    black_box<float>        var2 = 0.5f;

    std::list<Print *> pfmt;
    pfmt.push_back(&var0);
    pfmt.push_back(&var1);
    pfmt.push_back(&var2);

    dprintf(pfmt);
}



この投稿にコメントする

削除パスワード

No.23765

Re:動的に引数の個数、型が変化する printf
投稿者---しーまま(2005/10/21 12:27:12)


詳細なソースコードありがとうございます。
VC6.0 Console Application で、コンパイル・実行できました。

それで、一点教えていただきたいのですが、

"整数=%08d 文字列=%s 浮動小数点=%.3f\n"

といった書式で表示したい場合、
書式文字列はどこで指定すればよいのでしょうか?


>> 別のレスでも述べましたが、解析を全く行わずにできたはずです。
>
>解析を全く行わないプログラムです。





この投稿にコメントする

削除パスワード

No.23775

Re:動的に引数の個数、型が変化する printf
投稿者---かずま(2005/10/21 17:35:06)


> "整数=%08d 文字列=%s 浮動小数点=%.3f\n"
> といった書式で表示したい場合、
> 書式文字列はどこで指定すればよいのでしょうか?
void dprintf(std::list<Print *> &pfmt) の前に

#include <iomanip>

template<> void black_box<int>::print(std::ostream &o) {
    o << std::setfill('0') << std::setw(8) << val << std::setfill(' ');
}

template<> void black_box<float>::print(std::ostream &o) {
    int s = o.precision(3); o << std::fixed << val << std::setprecision(s);
}

----------------------------------------------------------------------
あるいは、

#include <cstdio>

template<> void black_box<int>::print(std::ostream &o) {
    char buf[32]; std::sprintf(buf, "%08d", val); o << buf;
}

template<> void black_box<float>::print(std::ostream &o) {
    char buf[320]; std::sprintf(buf, "%.3f", val); o << buf;
}



この投稿にコメントする

削除パスワード

No.23776

Re:動的に引数の個数、型が変化する printf
投稿者---かずま(2005/10/21 17:54:28)


この掲示板を見ている人の多くは C++ より、C のほうがなじみがあるよう
なので、参考のため C のプログラムを書いてみました。
#include <stdio.h>

typedef struct black_box {
    union { int i; float f; char *s; } var;
    int (*print)(struct black_box *, char *);
} black_box;

int print_i(black_box *bp, char *sp) { return sprintf(sp, "%08d", bp->var.i); }
int print_f(black_box *bp, char *sp) { return sprintf(sp, "%.3f", bp->var.f); }
int print_s(black_box *bp, char *sp) { return sprintf(sp, "%s",   bp->var.s); }

void dprintf(black_box *pfmt, int n)
{
    char buf[1024], *p = buf;  int i;
    if (n <= 0) return;
    p += pfmt->print(pfmt, p);
    for (i = 1; i < n; i++)
        *p++ = ' ', p += (pfmt+i)->print(pfmt+i, p);
    puts(buf);
}

int main(void)
{
    black_box pfmt[10];

    pfmt[0].var.i = 123;             pfmt[0].print = print_i;
    pfmt[1].var.s = "hello, world";  pfmt[1].print = print_s;
    pfmt[2].var.f = 0.5f;            pfmt[2].print = print_f;

    dprintf(pfmt, 3);
    return 0;
}



この投稿にコメントする

削除パスワード

No.23740

Re:動的引数の printf
投稿者---shu(2005/10/20 13:29:38)


>ヒントでもなんでも結構です。

断片的にいろいろとイメージしてみました。
使える考え方がもしあったら、
使えるところだけつまみ食いでもしてください。

//
fgets()での入力、
strtok()やsscanf()(この段階では、全て%sでのscan)、
その後データの内容を細かく確認しながら、
atoi(), atol(), atof(), strtol(), strtod()などで……

//
"100"というデータを、書式指定により、
整数の100や、実数の100.0で読みこんだり、

"100 100 100"というデータを、
"%d %f %s"という書式で読みこんでみたり、
"%d %d %d"という書式で読みこんでみたり、
"%s %f %f"という書式で読みこんでみたり、
"%s %f %s"という書式で読みこんでみたり、

"data100.200abc"というデータから、
"%s"という書式だと、全体文字列を読み込み、
"%d"という書式だと、100と200の二つのint型データを読みこみ、
"%f"という書式だと、100.200というfloat型データを読み込み……

//
書式の入力は自分で行うか、
あらかじめ良く使うパターンをいくつか用意しておくか……



この投稿にコメントする

削除パスワード

No.23758

Re:動的引数の printf
投稿者---しーまま(2005/10/20 18:08:32)


ありがとうございます。

ただ、何が来るかは実行時にしかわからないので、
予めパターンを予測するのは、ほぼ不可能だと思われます。


>>ヒントでもなんでも結構です。
>
>断片的にいろいろとイメージしてみました。
>使える考え方がもしあったら、
>使えるところだけつまみ食いでもしてください。
>
>
//
fgets()での入力、
strtok()やsscanf()(この段階では、全て%sでのscan)、
その後データの内容を細かく確認しながら、
atoi(), atol(), atof(), strtol(), strtod()などで……

//
"100"というデータを、書式指定により、
整数の100や、実数の100.0で読みこんだり、

"100 100 100"というデータを、
"%d %f %s"という書式で読みこんでみたり、
"%d %d %d"という書式で読みこんでみたり、
"%s %f %f"という書式で読みこんでみたり、
"%s %f %s"という書式で読みこんでみたり、

"data100.200abc"というデータから、
"%s"という書式だと、全体文字列を読み込み、
"%d"という書式だと、100と200の二つのint型データを読みこみ、
"%f"という書式だと、100.200というfloat型データを読み込み……

//
書式の入力は自分で行うか、
あらかじめ良く使うパターンをいくつか用意しておくか……




この投稿にコメントする

削除パスワード

No.23778

Re:動的引数の printf
投稿者---円零(2005/10/21 18:58:16)


正直申しますと私はこの長大なスレッドを全部読みこなしてないんですが、
気になるのは「動的な引数」がどういう形で引き渡されるのか明確でないように思われる点です。
動的な引数を処理するのはわかりましたが、ではその動的な引数をよこす関数は一体どのようなものなんでしょうか?
それをはっきりさせるのが先決のような気がするんですが…

仮にランダムに引数を生成する形でコードを書いてみましたがどうでしょう。

まあdprintfに渡す時点では既に「動的」ではなくなってしまってますが、
プログラム全体で言えば動的に発生するデータを処理してますよね?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

union UN {
    int i;
    double d;
    char *str;
};

int generate(union UN **u, char *format){  /* 「動的な引数」を生成 */
    int i, j, t, l;
    int count = rand() / (RAND_MAX / 10) + 1;
    if( !(*u = malloc(count * sizeof(union UN))) ) exit(1);
    for(i = 0; i < count; i++){
        t = rand() % 3;
        switch(t){
            case 0:
                (*u)[i].i = rand();
                strcat(format, "%d\n");
                break;
            case 1:
                (*u)[i].d = (double)rand() / (double)RAND_MAX;
                strcat(format, "%f\n");
                break;
            case 2:
                l = rand() % 10 + 1;
                if( !((*u)[i].str = calloc(l, 1)) ) exit(1);
                for(j = 0; j < l - 1; j++)
                    (*u)[i].str[j] = 'a' + rand() % 26;
                strcat(format, "%s\n");
        }
    }
    return count;
}

void dprintf(char *format, int count, union UN *u){
    int i, j;
    char buffer[256], *p = format;

    for(i = 0; i < count; i++){
        j = 0;
        while(p[j++] != '%' || p[j] == '%');
        j += strcspn(&p[j], "cdiouxefgps]");  /* 引数一つ分ごとに分解 */
        strncpy(buffer, p, ++j);
        buffer[j] = '\0';
        printf(buffer, u[i]);
        p += j;
    }
    if(*p) printf("%s", p);
}

int main(void){
    int count;
    char format[256] = {0};
    char *p = format;
    union UN *un;

    srand((unsigned)time(NULL));
    count = generate(&un, format);

    printf("書式制御文字列:\n");
    while(*p){
        if( *p++ == '\n' ) printf("\\n");
        else putchar(*p++);
    }
    printf("\n\n");

    dprintf(format, count, un);
    return 0;
}




この投稿にコメントする

削除パスワード

No.23782

Re:動的引数の printf
投稿者---しーまま(2005/10/22 02:10:19)


>正直申しますと私はこの長大なスレッドを全部読みこなしてないんですが、
>気になるのは「動的な引数」がどういう形で引き渡されるのか明確でないように思われる点です。
>動的な引数を処理するのはわかりましたが、ではその動的な引数をよこす関数は一体どのようなものなんでしょうか?
>それをはっきりさせるのが先決のような気がするんですが…
>

ありがとうございます。

No.23741 のサンプルコードを参照ください。



この投稿にコメントする

削除パスワード

No.23783

Re:動的引数の printf
投稿者---しーまま(2005/10/22 02:13:06)


みなさん、どうもありがとうございました。

あまりポピュラーな話題ではなかったようですね。

前にも書きましたが、再度ウェブを検索して、それらしいソースコードを探してみます。




この投稿にコメントする

削除パスワード

No.23785

Re:動的引数の printf
投稿者---RAPT(2005/10/22 10:27:59)


書式文字列を指定せず、関数へ渡した変数の型で判定するサンプルです。

C++でtypeidテンプレートを使用しています。

#include <typeinfo>
#include <iostream>
using namespace std;

void foo_impl(const void* pVal, const type_info& ti)
{
    if( ti == typeid(int) ){
        cout << "int: " << *static_cast<const int *>(pVal) << endl;
    }else if( ti == typeid(float) ){
        cout << "float: " << *static_cast<const float *>(pVal) << endl;
    }else if( ti == typeid(double) ){
        cout << "double: " << *static_cast<const double *>(pVal) << endl;
    }else if( ti == typeid(const char *) ){
        cout << "const char *: " << static_cast<const char *>(pVal) << endl;
    }else if( ti == typeid(const char) ){
        cout << "const char: " << *static_cast<const char *>(pVal) << endl;
    }else{
        cout << "others: " << pVal << endl;
    }
}

template<typename T>
inline void foo(const T& value)
{
    foo_impl(&value, typeid(value));
}

inline void foo<const char *>(const char * value)
{
    foo_impl(value, typeid(value));
}

int main()
{
    int a = 123;
    float b = static_cast<float>(6.51);
    char c = 'Q';
    const char *d = "A12345";
    size_t z = 5;

    foo( a );
    foo( b );
    foo( c );
    foo( d );
    foo( z );

    return 0;
}

----------[ 出力例 ]----------
int: 123
float: 6.51
const char: Q
const char *: A12345
others: 0012FF6C



この投稿にコメントする

削除パスワード

No.23787

Re:動的引数の printf
投稿者---かずま(2005/10/22 21:18:51)


> 書式文字列を指定せず、関数へ渡した変数の型で判定するサンプルです。

引数の型で判定するのなら、関数のオーバーロードを使ったほうがよいの
ではありませんか? if 文で判定し直す必要がなくなりますから。
#include <iostream>
using std::cout;
using std::endl;

template<typename T>
void foo(const T& value) { cout << "others: " << value << endl; }

void foo(int value)      { cout << "int: "    << value << endl; }
void foo(char value)     { cout << "char: "   << value << endl; }
void foo(float value)    { cout << "float: "  << value << endl; }
void foo(double value)   { cout << "double: " << value << endl; }
void foo(const char *value) { cout << "const char *: " << value << endl; }

int main()
{
    int a = 123;
    float b = 6.51f;
    char c = 'Q';
    const char *d = "A12345";
    size_t z = 5;

    foo(a);
    foo(b);
    foo(c);
    foo(d);
    foo(z);
}



この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧