7

I'm using swprintf to build a string into a buffer (using a loop among other things).

const int MaxStringLengthPerCharacter = 10 + 1;
wchar_t* pTmp = pBuffer;
for ( size_t i = 0; i < nNumPlayers ; ++i)
{
    const int nPlayerId = GetPlayer(i);
    const int nWritten = swprintf(pTmp, MaxStringLengthPerCharacter, TEXT("%d,"), nPlayerId);
    assert(nWritten >= 0 );
    pTmp += nWritten;
}

*pTaskPlayers = '\0';

If during testing the assert never hits, can I be sure that it will never hit in live code? That is, do I need to check if nWritten < 0 and handle that, or can I safely assume that there won't be a problem?

Under which circumstances can it return -1? The documentation more or less just states "If the function fails". In one place I've read that it will fail if it can't match the arguments (i.e. the formatting string to the varargs) but that doesn't worry me.

I'm also not worried about buffer overrun in this case - I know the buffer is big enough.

Srekel
  • 2,183
  • 3
  • 21
  • 26
  • 3
    As this is tagged C++, have you considered using stringstreams? Far more convenient. –  Jun 01 '10 at 08:55
  • It's important that the code is performant, which is why I've gone for a pre-allocated buffer string that I just copy into. I'm presuming that stringstreams might do a couple of memory allocations each time? – Srekel Jun 21 '10 at 08:42

4 Answers4

7

From the c99 standard:

The sprintf function returns the number of characters written in the array, not counting the terminating null character, or a negative value if an encoding error occurred.

This generally happens only with the multi-byte and wide character character set functions.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • This is entirely apropos, since the OP is in fact using the wide-character version `swprintf()`. – caf Jun 01 '10 at 10:31
  • Yep, but shouldn't be an issue so long as I know that I'm not using any "strange" characters I believe. – Srekel Jun 01 '10 at 14:29
3

It may fail with wrong format string, for example, which cannot happen in your case.

If buffer is not big enough, it may.

Otherwise, no reason for it to fail.

Pavel Radzivilovsky
  • 18,794
  • 5
  • 57
  • 67
2

In UNIX, it can fail:

 EILSEQ
       A wide-character code that does not  correspond  to  a
       valid character has been detected.

 EINVAL
       There are insufficient arguments.

EILSEQ has already been mentioned.

It may also fail, SIGSEGV, when the format specifier does not match the data - example using a %s format specifier with an int, 32 bit example:

int pdq=0xffffffff;
char tmp[32]={0x0};

sprintf(tmp, "%s", pdq);
jim mcnamara
  • 16,005
  • 2
  • 34
  • 51
  • FWIW like "insufficient arguments" and "mismatched format specifier" are undefined behavior per C99 draft (7.19.6.1). Perhaps specific compilers chose to define a particular behavior for them, but I'm not sure you can count on these failures generally on "UNIX". – BrodieG Aug 24 '20 at 12:31
2

I believe there is another case where snprintf() cannot succeed. It does not appear to be mentioned in POSIX or the current Linux manpage.

Upon successful completion, the snprintf() function shall return the number of bytes that would be written to s had n been sufficiently large excluding the terminating null byte.

snprintf() returns int. But an input string could be larger than INT_MAX.

sourcejedi
  • 3,051
  • 2
  • 24
  • 42