How do I define a function that accepts a formatted input string in C?

894 Views Asked by At

I built a custom logging function that takes in a "log level" and string. A user would specify the log level associated with the message (i.e. error, warning, trace, etc.). The logging function would only print the message to the console depending on the current log level configured.

int global_log_level = INFO;

void logger(int msg_log_level, char * msg)
{
    if(msg_log_level >= global_log_level )
    {
        printf("Log Level = %u: %s", msg_log_level, msg);
    }
}

Ideally, I want to feed formatted strings to this function.

logger(LOG_LEVEL_ERROR, "Error of %u occurred\n", error_code);

However, by adding this "wrapping" logic, I'm unable to input formatted message. Instead, I have to write the message to a temporary string and then feed that into the function.

char temp[512];
sprintf("Error of %u occurred\n", error_code);
logger(LOG_LEVEL_ERROR, temp);

Is there a way to implement the logger function such that I don't need to have the user create a temporary string themselves?

2

There are 2 best solutions below

2
On BEST ANSWER

This is question 15.5 on the C FAQ list.

You want vprintf, which lets you write your own printf-like function logger, but where you can pass the actual format string and arguments off to vprintf to do the work. The trick is that you need to construct a special va_arg type to "point to" the variable-length argument list. It looks like this:

#include <stdarg.h>

int global_log_level = INFO;

void logger(int msg_log_level, char * msg, ...)
{
    va_list argp;
    va_start(argp, msg);

    if(msg_log_level >= global_log_level )
    {
       printf("Log Level = %u: ", msg_log_level);
       vprintf(msg, argp);
    }

    va_end(argp);
}
0
On

As an addition to the @SteveSummit answer many compilers have special pragmas or attributes to indicate that the function is "printf-like". It allows the compiler to check parameters compile-time same as it is done when using printf

Example gcc :

format (archetype, string-index, first-to-check)

The format attribute specifies that a function takes printf, scanf, strftime or strfmon style arguments which should be type-checked against a format string. For example, the declaration:

              extern int
              my_printf (void *my_object, const char *my_format, ...)
                    __attribute__ ((format (printf, 2, 3)));
              

causes the compiler to check the arguments in calls to my_printf for consistency with the printf style format string argument my_format. The parameter archetype determines how the format string is interpreted, and should be printf, scanf, strftime or strfmon. (You can also use __printf__, __scanf__, __strftime__ or __strfmon__.) The parameter string-index specifies which argument is the format string argument (starting from 1), while first-to-check is the number of the first argument to check against the format string. For functions where the arguments are not available to be checked (such as vprintf), specify the third parameter as zero. In this case the compiler only checks the format string for consistency. For strftime formats, the third parameter is required to be zero.

In the example above, the format string (my_format) is the second argument of the function my_print, and the arguments to check start with the third argument, so the correct parameters for the format attribute are 2 and 3.

The format attribute allows you to identify your own functions which take format strings as arguments, so that GCC can check the calls to these functions for errors. The compiler always (unless -ffreestanding is used) checks formats for the standard library functions printf, fprintf, sprintf, scanf, fscanf, sscanf, strftime, vprintf, vfprintf and vsprintf whenever such warnings are requested (using -Wformat), so there is no need to modify the header file stdio.h. In C99 mode, the functions snprintf, vsnprintf, vscanf, vfscanf and vsscanf are also checked. Except in strictly conforming C standard modes, the X/Open function strfmon is also checked as are printf_unlocked and fprintf_unlocked. See Options Controlling C Dialect.

Source: https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Function-Attributes.html