baeda baeda - 18 days ago 9
C Question

Variadic logger dispatcher

I am implementing sort of a logging dispatcher, i.e.

int32_t logf(const char *fmt, ...);
which outputs to different logging targets, depending on which options it was compiled with.

The following is a boiled down excerpt.

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


Now... If no options are given, the logger would (and actually is intended to) be a null-logger. However, do I then still need the calls to
va_start()
and
va_end()
in there?

In other words (ignoring -Wunused-label for a second), is this correct:

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

va_start(va, fmt);

res = S_PASS;

exit:
va_end(va);

return res;
}


...or this?

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

res = S_PASS;

return res;
}


UPDATE

The resulting empty function implementation cannot be replaced by a function-style macro like
#define logf(fmt, ...) S_PASS;
.

The existing code base has defined
typedef int32_t(*logFunc)(const char *fmt, ...);
and therefore pointers to logf must be storable.

Answer

If no logging was enabled, I would suggest you instead had simply an empty function, or maybe a variadic macro that expands to S_PASS.

Perhaps something like

#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

The above is if you define the function in your header. If you only have a declaration in your header with the definition in a source file it's almost the same.

Header file:

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

Source file:

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

After your comment about function pointers, then the best solution is probably to have a inline function function which only does returnS_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
Comments