Search code examples
cargument-passingc89

How to write a vfprintf wrapper that adds a prefix to format specifier and passes the new format specifier to vfprintf in C89?


I am trying to write a wrapper around vfprintf function but with the requirement that I want to add a prefix to the format specifier and then pass the new format specifier to vfprintf.

Now I don't know how to do this, but I have captured my intention in the following code.

#include <stdio.h>
#include <stdarg.h>

void err(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    vfprintf(stderr, "foo: error:" format, args);
    va_end(args);
}

int main()
{
    err("%s: %d\n", "Transaction failed with error code", 42);
    return 0;
}

You can see in the above code, that I want to prefix "foo: error" to the format specifier and then pass it to vprintf. This code, of course, would lead to compile time error because this code is not valid. It only captures my intention of what I am trying to achieve.

lone@debian:~/lab/c$ gcc -std=c89 -Wall -Wextra -pedantic vfprintf-wrapper.c 
vfprintf-wrapper.c: In function ‘err’:
vfprintf-wrapper.c:8:36: error: expected ‘)’ before ‘format’
     vfprintf(stderr, "foo: error:" format, args);
                                    ^
vfprintf-wrapper.c:8:5: error: too few arguments to function ‘vfprintf’
     vfprintf(stderr, "foo: error:" format, args);
     ^

Can you help me to write this code correctly?


Solution

  • Your pseudocode vfprintf(stderr, "foo: error:" format, args); should be:

    fprintf(stderr, "foo: error:");
    vfprintf(stderr, format, args);
    

    You seem to be indicating that you want to avoid the "extra" fprintf call. If so then you could do this:

    char *fail = malloc(sizeof "foo: error:" + strlen(format));
    if ( !fail )
        exit(EXIT_FAILURE);
    strcpy(fail, "foo: error:");
    strcat(fail, format);
    
    vfprintf(stderr, fail, args);
    
    free(fail);
    

    although that would be a waste of time and resource.