Returning the formatted string from the C function

advertisements

I'm trying to write a recursive function for printing a tree-like structure. What I want to do is roughly as follows. Assume form is a function that takes the same arguments as printf, but returns the formatted string instead of printing it; Node is the struct that the structure is built from, with a val slot storing an unsigned long.

char* vals(Node* u) {
    if (leaf(u)) {
        return form("%lu", u->val);
    } else {
        return form("%s, %s", vals(u->left), vals(u->right);
    }
}

I'm not sure how to write this, as I've not been able to find a function similar to form.


As it happens, I have an implementation (two implementations, actually) of that function here at line 77 or so. It's just a simple wrapper designed to make calling the function easier; there are more efficient solutions but it doesn't usually make much difference.

/* Like GNU asprintf, but returns the resulting string buffer;
 * it is the responsibility of the caller to freee the buffer
 */
char* concatf(const char* fmt, ...);

The first one relies on vasprintf, which is a non-standard function which is part of Gnu glibc:

char* concatf(const char* fmt, ...) {
  va_list args;
  char* buf = NULL;
  va_start(args, fmt);
  int n = vasprintf(&buf, fmt, args);
  va_end(args);
  if (n < 0) { free(buf); buf = NULL; }
  return buf;
}

The second one relies on vsnprintf, which is a Posix-standard interface but was incorrectly implemented in some older standard C library implementations (glibc until version 2.0.6, for example.)

char* concatf(const char* fmt, ...) {
  va_list args;
  va_start(args, fmt);
  char* buf = NULL;
  int n = vsnprintf(NULL, 0, fmt, args);
  va_end(args);
  if (n >= 0) {
    va_start(args, fmt);
    buf = malloc(n+1);
    if (buf) vsnprintf(buf, n+1, fmt, args);
    va_end(args);
  }
  return buf;
}

Feel free to use them as you need them. They're not particularly profound.

For gcc (and, I think, clang), you can declare the function as:

char* concatf(const char *fmt, ...)
      __attribute__ ((format (printf, 1, 2)));

which will enable the compiler to check the validity of the format string, as it does with printf