1

I have used variadic functions to wrap printf (or vprintf).

The following code works except for making mistake on the first variadic argument to warning_printf. Also, placing the string directly will change the ASCII character but it does not fix it as the message is still random.

What it prints is

[Warning]
          ®¯$ address: 0x87afae8a

Instead of

[Warning] Failed to initialize setting address: 0x87afae8a

Where the word Warning is colored properly (anyway it does not matter). But the msg_warn seems not being passed correctly. I tested adding more variables to this function. They all work fine except for only the first variadic argument msg_warn.

What is wrong with my code?

void colorful_printf( const char* header, const char* color, const char* fmt, ... )
{
    printf("[%s%s%s] ", color, header, RESET_ANSI_COLOR);
    va_list args;
    va_start( args, fmt );
    vprintf(fmt, args);
    va_end( args );
}


void warning_printf( const char* fmt, ... )
{
    va_list args;
    va_start( args, fmt );
    colorful_printf("Warning", WARNING_COLOR, fmt, args);
    va_end( args );
}


char msg_warn[] = "Failed to initialize setting";
warning_printf( "%s address: 0x%2x", msg_warn, address );

Online compiler: link

4
  • 1
    You need a function that takes a va_list instead of .... Commented Apr 12, 2019 at 0:36
  • @JonathanLeffler, by copy or by reference? Commented Apr 12, 2019 at 0:38
  • By copy. I think Repeated use of a variadic function argument doesn't work has relevant material, but I also think I've written a more relevant answer — I just can't find it. Sometimes, it is easier to write the answer over than to find the right Q&A. Commented Apr 12, 2019 at 0:40
  • Th question Passing variable arguments to another function that accepts a variable argument list is tagged for C++, but the answer applies equally to C. It covers the same territory as my answer below — you create the function that takes the va_list instead of ... and the ... functions create a va_list and then call the function that takes the va_list to do the real work. We will need to come to a consensus on whether it is OK as a duplicate despite the mismatch between C++ and C, or contemplate retagging it as C++ and C (ouch!). Commented Apr 12, 2019 at 0:59

1 Answer 1

2

You need to pass the va_list to a function that expects them — an analogue to the v*printf() functions.

void colorful_vprintf(const char* header, const char* color, const char* fmt, va_list args)
{
    printf("[%s%s%s] ", color, header, RESET_ANSI_COLOR);
    vprintf(fmt, args);
}

void colorful_printf(const char* header, const char* color, const char* fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    colorful_vprintf(header, color, fmt, args);
    va_end(args);
}

void warning_vprintf(const char* fmt, va_list args)
{
    colorful_vprintf("Warning", WARNING_COLOR, fmt, args);
}

void warning_printf(const char* fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    warning_vprintf(fmt, args);
    va_end(args);
}

The *_vprintf functions do the real work; the functions that have ellipsis simply get the va_list for the arguments and pass them to the *_vprintf() functions. This is a general pattern for interfaces to (wrappers around) the printf() family of functions.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.