Home > Enterprise >  Replace C varargs with modern C equivalent construct
Replace C varargs with modern C equivalent construct

Time:12-05

I am attempting to rewrite old C code in its C equivalent. The module i am working on seem to use C variable arguments list alot. One of the common usage example is as follows (PLEASE NOTE THAT BELOW CODE IS JUST INDICATIVE EXAMPLE, its not actual production code. MY INTENTION IS TO REWRITE THE USAGE OF VARARGS with Modern C constructs) :

#include <stdio.h>
#include <stdarg.h>
 
void simple_printf(const char* fmt, ...)
{
    va_list args;
    va_start(args, fmt);
 
    while (*fmt != '\0') {
        if (*fmt == 'd') {
            int i = va_arg(args, int);
            printf("%d\n", i);
        } else if (*fmt == 'c') {
            // A 'char' variable will be promoted to 'int'
            // A character literal in C is already 'int' by itself
            int c = va_arg(args, int);
            printf("%c\n", c);
        } else if (*fmt == 'f') {
            double d = va_arg(args, double);
            printf("%f\n", d);
        }
          fmt;
    }
 
    va_end(args);
}
 
int main(void)
{
    simple_printf("dcff", 3, 'a', 1.999, 42.5); 
}

I am interested in knowing what are the alternatives available in Modern C to rewrite this code something similar as above. I am also interested in knowing multiple options available in Modern C . A code example will be more beneficial.

CodePudding user response:

The only thing "special" that this function does it puts a newline after each arguments. In c 17 you can do that with fold expression:

template<typename... Args>
void print(Args... args) {
    ((std::cout << args << '\n'), ...); 
}

In older versions you can do it with recursion:

template<typename T>
void print(T value) {
  std::cout << value << std::endl;
}

template<typename T, typename... Args>
void print(T value, Args... args) {
  print(value);
  print(args...);
}

Anyway this is a bit odd. Modern C would use format. Either the fmt library or the C 20 standard format library:

std::cout << std::format("{}\n{}\n{}\n{}\n", 3, 'a', 1.999, 42.5);

And in C 23:

std::print(std::cout, "{}\n{}\n{}\n{}\n", 3, 'a', 1.999, 42.5);

CodePudding user response:

You can get rid of this function completely. Throw it away. Hit the "Delete" button.

simple_printf("dcff", 3, 'a', 1.999, 42.5); 

In C this becomes:

std::cout << 3 << "\n" << 'a' << "\n" << 1.999 << "\n" << 42.5 << "\n";

No function is necessary. And, this is even safer than the C version, which you could still misuse by giving the wrong formatting string. The C version is bulletproof.

And this isn't exactly "modern" C . You could've done that right from the beginning, pretty much.

I suppose you can replace this with a template function, to add a newline automatically, but this would be overkill. This is simple enough without adding this kind of complexity.

  • Related