The vprintf family of functions is available on many systems, and source is available for any systems which do not provide it as standard.

http://www.ijs.si/software/snprintf/ is one portable implementation.

But there are problems using vsnprintf() portably. When the provided buffer is not large enough to hold the entire formatted string, the string will be truncated. However, it can be difficult to determine if the formatted string actually has been truncated or not. The return values vary from system to system.

Experiments

Experiments were done on a number of systems to see how short buffers are handled. Here is a listing of the different things that happen:

  • vsnprintf() returns -1, but provides no clue as to how big the buffer should be.
  • vsnprintf() returns a value equal to the buffer size passed, but provides no other clue about how big the buffer should be.
  • vsnprintf() returns a value equal to the buffer size passed, minus 1. This should indicate the formatted string, plus terminal \0 fit exactly. But on some systems, the string was silently truncated to fit the given buffer size.
  • vsnprintf() returns a value larger than the given buffer size. In this case, the formatted string was truncated, but vsnprintf() is telling us how big we need to make the buffer.

Solution

To use vsnprintf() portably, we must enclose it in a loop and repeatedly call it with ever bigger buffers until it is clear the formatted string has not been truncated. The return value must be carefully checked, and unless we are certain the output has not been truncated, we must grow the buffer and try again.

pasprintf.c is an example implementation of asprintf() written using vsnprintf(). It has been tested several UNIX-like systems, and should compile without change on all modern systems.