Watch out for sprintf()!

I was looking at some code the other day that does string concatenation with StringCchPrintf(“%s%s”).  I can imagine how this would have near optimal performance, and a hopeful developer could easily assume that in fact it has been tuned for this kind of concatenation.  But measuring tells all.  Three trivial implementations of concat using strsafe.h:

 void concat_printf(PCWSTR str1, PCWSTR str2, PWSTR out, size_t max)
{
    StringCchPrintfW(out, max, L"%s%s", str1, str2);
}

void concat_copy(PCWSTR str1, PCWSTR str2, PWSTR out, size_t max)
{
    StringCchCopyEx(out, max, str1, &out, &max, 0);
    StringCchCopy(out, max, str2);
}

void concat_cat(PCWSTR str1, PCWSTR str2, PWSTR out, size_t max)
{
    StringCchCopy(out, max, str1);
    StringCchCat(out, max, str2);
}

Measurements for short concatenating strings (~10 chars) and long strings (~1000 chars).

method short long
concat_printf 187 10530
concat_copy 15 952
concat_cat 15 1264

Unsurprisingly concat_copy() is the most efficient, with concat_cat() overhead of a strlen() only noticeable with longer strings.  But wow, concat_printf() is shocking order of magnitude slower than either of the others.  Taking a peak under the covers explains why:  MSVCRT is using a FILE* stream abstraction that does a lot more work for every character copy.  This is so the code for printf(), fprintf() and sprintf() can all be shared.  Generalization at the cost of performance!