2016-11-16 31 views
1

我正在實現一種記錄調度器,即int32_t logf(const char *fmt, ...);,它根據編譯的選項輸出到不同的記錄目標。可變參數記錄器調度器

以下是一段簡短的摘錄。

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

可變宏應擴展爲'S_PASS'以匹配空函數的返回值。 – mch

+0

是的,這大部分與第二個變體相同。但是,這是正確的嗎?我可以只向函數聲明可變參數,不要使用va_start和va_end? – baeda

+0

@mch是的你是對的。相應地更新答案。 –

1

這是一個有點爭議點,因爲當你建議只有一個可變參數函數你在拍攝自己的腳。你的可變參數函數應該永遠是一個包裝到va_list之一:

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