10

A (very long) while ago I regularly used the following code - then on MSVC 6 - to determine the memory needed to format a string for a function with variadic arguments:

void LogPrint(const char *pszFormat, ...)
{
    int          nBytes;
    char        *pszBuffer;
    va_list      args;

    va_start(args, pszFormat);
    nBytes = vsnprintf(0, 0, pszFormat, va);
    va_end(args);

    // error checking omitted for brevity
    pszBuffer = new char[nBytes + 1];

    va_start(args, pszFormat);
    vsnprintf(pszBuffer, nBytes, pszFormat, va);
    va_end();

    // ...
}

The obvious error you're getting in a more recent version of MSVC (I'm using 2010 now) is:

warning C4996: 'vsnprintf': This function or variable may be unsafe. Consider using vsnprintf_s instead. To disable deprecation use _CRT_SECURE_NO_WARNINGS. See online help for details.

I'm a big fan of the "treat warnings as errors" option for any C(++)-compiler, and obviously my build fails. It feels like cheating to me to simply employ #pragma warning (disable:4996) and get on with it.

The suggested "safer" alternative vsnprintf_s(), however is doomed to return -1 when input conditions of its "unsafe" predecessor occur.

TL/DR: Is there a way to implement the expected behavior of vsnprintf() to return the memory needed to fulfil its task using the new, safer variants of it?


EDIT: simply defining _CRT_SECURE_NO_WARNINGS won't cut it; there's a lot of strcpy() flying around, too. The new variant of which isn't broken, so I'd like to still see these.

Linus Kleen
  • 33,871
  • 11
  • 91
  • 99
  • `vsprintf_s` is not only m$ only (and thus unportable), it is said by many people that its sole purpose to exist is to tighten your vendor lock-in, so have you thought about disabling the suggestion to replace all standard calls by _s variants? – PlasmaHH Feb 20 '12 at 22:03
  • 1
    @PlasmaHH: C11 contains the `_s` functions as recommendations in the optional Appendix K. – Kerrek SB Feb 20 '12 at 22:04
  • Yeah. I have. But as I said, it feels like cheating to me. After all - apart from vendor-locking software - someone must have thought of `vsnprintf()`'s nifty feature *before* making it unavailable? – Linus Kleen Feb 20 '12 at 22:05
  • The rest of the warning, which you did not include in your question, is a #define you can set to avoid this vendor-specific warning. I suppose that's no different than the pragma you posit, but either method should be fine. – mah Feb 20 '12 at 22:06
  • According to C99, you can pass size zero and a null pointer to `(v)snprintf` and obtain the required output size as the return value. – Kerrek SB Feb 20 '12 at 22:07
  • Have you considered using a type-safe templated printf() variant or iostreams-based code instead? That will give you more safety than vsnprintf_s can, and surely the point should be to fix the problem that the warning indicates rather than just tweaking the code to avoid the warning. – John Bartholomew Feb 20 '12 at 22:10
  • @KerrekSB ...which is why the above code worked then. Its allegedely "safer" successor doesn't, however. – Linus Kleen Feb 20 '12 at 22:30
  • Possible duplicate of [Determining sprintf buffer size - what's the standard?](https://stackoverflow.com/questions/3919995/determining-sprintf-buffer-size-whats-the-standard) – Regis Portalez Jul 05 '17 at 09:19

1 Answers1

15

The function you want to look at is _vscprintf, which "returns the number of characters that would be generated if the string pointed to by the list of arguments was printed or sent to a file or buffer using the specified formatting codes". There's a widechar variant (_vscwprintf) as well.

Chris J
  • 30,688
  • 6
  • 69
  • 111