2016-11-16 14 views
1

私はどの種類のオプションをコンパイルしたかに応じて、さまざまなロギングターゲットに出力する、つまり、int32_t logf(const char *fmt, ...);という種類のロギングディスパッチャを実装しています。Variadic Loggerディスパッチャ

以下は、抜粋の抜粋です。何もオプションが指定されていない場合

int32_t logf(const char *fmt, ...) 
{ 
    va_list va; 
    i32  res; 

    va_start(va, fmt); 

    res = S_PASS; 

#ifdef LOG_UART 
    res = Uart_vprintf(fmt, va); 
    if (res != S_PASS) goto exit; 
#endif /* LOG_UART */ 

#ifdef LOG_SYS 
    res = System_vprintf(fmt, va); 
    if (res != S_PASS) goto exit; 
#endif /* LOG_SYS */ 

exit: 
    va_end(va); 

    return res; 
} 

は今...、ロガーは、ヌル・ロガーこと(そして実際にすることを意図している)でしょう。しかし、そこにはまだva_start()va_end()へのコールが必要ですか?つまり(秒-Wunused-ラベルを無視して)で

、これは正しいです:

int32_t logf(const char *fmt, ...) 
{ 
    va_list va; 
    i32  res; 

    va_start(va, fmt); 

    res = S_PASS; 

exit: 
    va_end(va); 

    return res; 
} 

...またはこれ?

int32_t logf(const char *fmt, ...) 
{ 
    i32  res; 

    res = S_PASS; 

    return res; 
} 

UPDATE

関数の実装は、#define logf(fmt, ...) S_PASS;ような関数形式のマクロに置き換えることができません。

既存のコードベースはtypedef int32_t(*logFunc)(const char *fmt, ...);と定義されているため、logfへのポインタは格納可能でなければなりません。

答えて

3

ロギングが有効になっている場合は、単に空の関数、またはS_PASSに展開する可変マクロを使用することをお勧めします。あなたは、ヘッダー内の関数を定義した場合

おそらく何か上記


#if defined(LOG_UART) || defined(LOG_SYS) 
inline int32_t logf(const char *fmt, ...) 
{ 
    // Your original code here... 
} 
#else 
# define logf(x, ...) S_PASS 
#endif 

のようなものです。ヘッダーにソースファイルの定義を持つ宣言だけがあれば、ほぼ同じです。

ヘッダファイル:

#if defined(LOG_UART) || defined(LOG_SYS) 
int32_t logf(const char *fmt, ...); 
#else 
# define logf(x, ...) S_PASS 
#endif 

ソースファイル:関数ポインタについてコメントした後

#if defined(LOG_UART) || defined(LOG_SYS) 
inline int32_t logf(const char *fmt, ...) 
{ 
    // Your original code here... 
} 
#endif 

は、その後、最善の解決策は、インライン関数の機能を持つことが、おそらくあるのみreturn S_PASS`:

#if defined(LOG_UART) || defined(LOG_SYS) 
int32_t logf(const char *fmt, ...); 
#else 
inline int32_t logf(const char *fmt, ...) { return S_PASS; } 
#endif 
+0

空の関数の戻り値と一致するように、variadicマクロは 'S_PASS'に展開する必要があります。 – mch

+0

そうです、それは第2の変種とほとんど同じです。それでも正しいのですか?私は、関数にバリデーショナルなパラメータを宣言し、va_startとva_endを使用しないことができますか? – baeda

+0

@mchはい、あなたは正しいです。それに応じて答えを更新。 –

1

バリデーショナル機能を提案したときに足で自分自身を撃っているので、それはちょっとした問題です。あなたの可変引数関数は常にva_list 1にラッパのようになります。

int32_t vlogf(const char *fmt, va_list va); 

int32_t logf(const char *fmt, ...) 
{ 
    int32_t res; 
    va_list va; 
    va_start(va, fmt); 

    res = vlogf(fmt, va); 

    va_end(va); 
} 

また、あなたが二度同じva_listを使用することになっていないので、両方のマクロが定義されている場合、あなたはそれva_copyする必要があります。

int32_t vlogf(const char *fmt, va_list va) 
{ 
    i32  res; 

    res = S_PASS; 

#if defined(LOG_UART) && defined(LOG_SYS) 

    /*Can't use the same va_list twice: */ 
    /*If both are defined, need to use va_copy*/ 
    { 
     va_list va2; 
     va_copy(va2, va); 

     res = Uart_vprintf(fmt, va); 
     if (res != S_PASS) goto exit2; 

     res = System_vprintf(fmt, va); 
    exit2: 
     va_end(va2); 
    } 
    if (res != S_PASS) goto exit; 

#elif defined(LOG_UART) 
    res = Uart_vprintf(fmt, va); 
    if (res != S_PASS) goto exit; 
#elif defined(LOG_SYS) 
    res = System_vprintf(fmt, va); 
    if (res != S_PASS) goto exit; 
#endif /* LOG_SYS */ 

exit: 
    return res; 
} 
+0

va_listをコピーし、別のvlogfでラップすることについての非常に有用な情報! – baeda