Variadic记录器调度员

时间:2016-11-16 09:44:31

标签: c variadic-functions

我正在实现一种日志记录调度程序,即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-label一秒),这是正确的:

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;
}

更新

生成的 empty 函数实现不能被像#define logf(fmt, ...) S_PASS;这样的函数式宏替换。

现有代码库已定义typedef int32_t(*logFunc)(const char *fmt, ...);,因此指向logf的指针必须是可存储的。

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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;
}