21

I was looking to implement an api like printf for my logging. It should be similar to calling printf. For example:

persistent_log(LogType0, "This is buffered writing %d", i);

I looked into variable argument stuff , but it seems I need to know the number & type of arguments there. so I need more help in that regard.

8
  • Do you want to use C++0x or C style va_args? Commented Aug 11, 2011 at 18:43
  • @awoodland , C style va_args Commented Aug 11, 2011 at 18:47
  • cboard.cprogramming.com/c-programming/… Commented Aug 11, 2011 at 18:48
  • Note that you won't be able to check types in compile time if you use va_args approach. If you're OK with C++, use Boost.Format or roll up a solution on templates. Otherwise just accept the lack of type safety. Commented Aug 11, 2011 at 18:52
  • 3
    Since you want to use va_args I'm removing the C++ tag. Commented Aug 11, 2011 at 19:02

3 Answers 3

28

Here's an excerpt from a past project that I found to work well for me. Some initialization steps are of course missing. The key here is the vfprintf function which will handle the details of printing the various arguments.

void _proxy_log(log_level_t level, const char *fmt, ...)
    __attribute__((format (printf, 2, 3)));

#define proxy_log(level, fmt, ...) _proxy_log(level, fmt"\n", ##__VA_ARGS__)

void _proxy_log(log_level_t level, const char *fmt, ...) {
    va_list arg;
    FILE *log_file = (level == LOG_ERROR) ? err_log : info_log;

    /* Check if the message should be logged */
    if (level > log_level)
        return;

    /* Write the error message */
    va_start(arg, fmt);
    vfprintf(log_file, fmt, arg);
    va_end(arg);

#ifdef DEBUG
    fflush(log_file);
    fsync(fileno(log_file));
#endif
}
Sign up to request clarification or add additional context in comments.

4 Comments

+1. Not too many people are aware of GCC's __attribute__((format(...))) facility to add compile-time type-checking.
Good point. Here's a link to the documentation
To help future travelers: the first line, from 'void _prox...' to '2,3)));' is all the function declaration and goes into the *.h. The #define can pretty much go anywhere after the function is declared, and the implementation is the last bit. Maybe it's obvious, but I was confused for a while!
@Hamy The #define is not a function declaration, but it's true that those lines should go in the header.
4

Using "va_arg" http://www.cplusplus.com/reference/clibrary/cstdarg/va_arg/

2 Comments

but I willneed to knwo the type before hand for this
You learn that from inspecting the format string yourself (if you really want to have fun). Alternately, and this is easier, just dispatch to vfprintf when you've pulled your custom arguments out.
3

This is an old question, but here is my simplified base solution that exactly mimics printf and should be expandable to other more specific uses, it's basically a generalized version of Michael Mior's answer:

#include <stdarg.h>

void print(const char* fmt, ...)
{
    va_list arg;
    va_start(arg, fmt);

    vprintf(fmt, arg); 
    //vprintf can be replaced with vsprintf (for sprintf behavior) 
    //or any other printf function preceded by a v

    va_end(arg);
}

(This seems to work in c++ as well)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.