1

I was writing a utility function to do sprintf like formatting for std::string or std::wstring based on Unicode settings.

#ifdef _UNICODE
typedef std::wstring MyString ;
typedef TCHAR MyChar ;
#define MYTEXT TEXT
#else
typedef std::string MyString ;
typedef char MyChar ;
#define MYTEXT
#endif //_UNICODE

MyString Utils::GetStringPrintf(const MyString kstrText, ...)
{
    int iCharsWritten = 0 ;
    MyString strFinal ;
    MyChar szBufferTouse[8194] ; //Hopefully Long enough
    va_list     fmtList ;
    va_start(fmtList, kstrText) ;
    /*int iVal = va_arg(fmtList, int) ;*/ =>Just for debugging

#ifdef _UNICODE
    iCharsWritten = _stprintf_s(szBufferTouse,  8194, kstrText.c_str(), fmtList) ;
#else
    iCharsWritten = sprintf_s(szBufferTouse, 8194, kstrText.c_str(), fmtList) ;
#endif //_UNICODE

    va_end(fmtList) ;
    strFinal = szBufferTouse ;
    return strFinal ;
}

When called like :

int iId = 2 ;
MyString strFileName = Utils::GetStringPrintf(MYTEXT("Student_%d.png"), iId) ;  

//For Unicode am getting Student_1633600.png instead of Student_2.png //For non-Unicode am getting Student_1633800.png instead of Student_2.png

Upon debugging I do get the value of iVal as 2, but somehow the values get bad upon passing to sprintf.

However if I call, sprintf directly,

MyChar szFilename[200] ;
int iId = 2 ;
_stprintf_s(szFilename, 200, MYTEXT("Student_%d.png"), iId) ;

Am getting proper output, i.e Student_2.png

I did refer other posts in Stack Overflow regarding sprintf functionality and found my code to be doing quite similar to those. Is there any problem in passing va_list repeatedly to functions.

1
  • 1
    Totally unrelated but very life-saving tip: drop the silly TCHAR and _UNICODE business ASAP. Do you really want to support Win98? Because that is essentially the only reason for its use. Either use wchar_t and be able to call the "wide" Win32 API functions directly, or use char and UTF-8, and convert when you need to. If you really need full-blown no-exceptions Unicode, use something like ICU and don't do it yourself. Commented Apr 29, 2014 at 12:29

1 Answer 1

1

Replace sprintf_s with vsprintf(and remove size) or with vsprintf_s if available.

Quoting from manpage of printf. (Emphasis mine)

The functions vprintf(), vfprintf(), vsprintf(), vsnprintf() are equivalent to the functions printf(), fprintf(), sprintf(), snprintf(), respectively, except that they are called with a va_list instead of a variable number of arguments. These functions do not call the va_end macro. Because they invoke the va_arg macro, the value of ap is undefined after the call.

Sign up to request clarification or add additional context in comments.

2 Comments

@alk Thanks for extending the answer and make it more useful. I believed it exists if sprintf_s does. Because it is the building block for sprintf. But I am not sure about the MS environment and their safe function implementation so warned OP to check availability. vprintf on the other hand is guaranteed to exist.
@MohitJain Thanks for the answer and indeed it worked like a charm. For Windows environment, StringCchVPrintf can also be used.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.