2017-01-25 3 views
3

私はいくつかのデータをいくつかのファイルに書き込むログサービスを作成しています(ファイル名はログとしましょう)。特定の引数がCの型[変数引数]であることを知らずにアクセスするにはどうすればよいですか?

書きたいデータの種類は、int型や文字列型などさまざまです。

void write_log(FILE * fp, char * event, ...) 
{ 
    va_list list; 
    va_start(list, event); 
    // Cannot use va_arg(list, type_of_var) here!!! 
} 

私は関数が私のデータに応じて異なる場合があります呼び出す方法:私が持っている

write_log(fp, "Memory size :", mem_size); 

それとも

write_log(fp, "Username :", username); 

は、これまでのところ、これは私の機能がどのように見えるかです3番目の引数が文字列かintか他のものかどうかは考えられません。

私はva_arg(list, type_of_var)を使用していた可能性がありますが、私のデータのタイプは任意に変化しますので使用できません。

関数の第3引数にどのようにアクセスすることができますか?

+3

できません。なぜprintfのような関数が書式文字列を必要とすると思いますか? – DeiDei

+0

私の機能のアイデアや回避策は? –

+2

回避策:必要なフィールドで 'struct'を定義し、それをファイルに書き込む関数に渡します。この関数は、構造体から関連するデータを読み込んでログに書き出します。 – ThunderWiring

答えて

4

タイプが何であるかを知るための移植可能な標準的な方法はありません。

頭に浮かぶ最初の解決策は、フォーマット文字列(たとえばprintfscanf)を渡す必要があるという、よく知られているCイディオムを使用することです。

void write_log(FILE * fp, char * event, const char* fmt, ...) 
{ 
    va_list list; 
    va_start(list, event); 

    // process fmt and act accordingly 
} 

それが唯一の追加のパラメータになるだろう場合、あなたはenumを渡すことができます。

enum type { 
    integer, 
    pointer, 
    floating 
}; 

void write_log(FILE * fp, char * event, enum type t, ...) 
{ 
    switch(t) 
    { 
    case integer: // do stuff with integer 
    case pointer: // do stuff with pointer 
    } 
} 

あなたはC11の_Generic機能へのアクセスを持っている場合は、最新のコンパイラがそうであるように、あなたが何かを持つことができます並べ替え:

void write_logi(FILE * fp, char * event, int); 
void write_logf(FILE * fp, char * event, float); 
void write_logfoo(FILE * fp, char * event, struct foo); 

#define write_log(file, event, arg) _Generic((arg), \ 
    int: write_logi,        \ 
    float: write_logf,        \ 
    struct foo: write_logfoo      \ 
)(file, event, arg) 

次に、あなたのように呼び出すことができます10

write_log(fp, event, i/*int*/); 
write_log(fp, event, f/*float*/); 

となり、適切な機能が選択されます。

+1

UVは '_Generic'のためのものです。これは、以前に定義されたセットに限られていますが、タイプが何であるかを知るための移植可能な方法です。 – chux

+0

これは機能しました。ありがとう! –

関連する問題