# Customizing (or rather extending) sprintf()

This topic is 1696 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I want to extend the regular sprintf() to take advantage unknown string lengths and my own memory manager. Hence I set out to write a little wrapper to precalculate the string length, allocate it manually and then do the sprintf() operation. This seemed like a straightforward task until it started crashing my program. As it stands, working out what is wrong has proven to be somewhat of a formidable task. Here's my initial code:

ISharedPtr<char> SPRINT(IN ISharedPtr<char>& buf, char * fmt, ...)
{
va_list ap;
int iFmtLen = 0;

if(fmt == NULL)
{ return buf = null; }

//if buf is allocated, free it
if(buf != null)
{ Delete(buf); }

va_start(ap, fmt);
//#get the length
#ifdef WIN32
//I was using the VC version of snprintf(), but it started crashing so after a bit of googling
//it turned out _scprintf() should be specialized for the task. It fails in the same way.
iFmtLen = _scprintf(fmt, ap);//_snprintf(NULL, 0, fmt, ap); // <- PROBLEM HERE
#else
iFmtLen = snprintf(NULL, 0, fmt, ap);
#endif

//use my allocator
buf = NewArray(char, iFmtLen + 1);

//do regular sprintf()
vsprintf(buf.ptr, fmt, ap);
va_end(ap);

return buf;
}



The symptoms: granted, I don't know the printX() functions in detail, but my first question arises when outputting the fmt argument after entering SPRINT(). It shows up as:

fmt before entering SPRINT(): '%d'

fmt when output to console from inside SPRINT(): '4245253'

Inspecting fmt while debugging shows the expected '%d'

Passing the format directly to _scprintf() like so:

_scprintf("'%d", 100000000);

produces the expected length of 9. Passing it as it is in the code produces 7 or some similar incorrect result. What totally screws everything up and causes the entire program to crash inside output.c (SDK file), though, is passing a string in as a variadic argument: fmt = "%s"

All arguments are correct and all variadic types match the format. What am I missing here?

PS - I would appreciate not being reminded that I should be using boost::shared_ptr or whatnot.

Edit: the title is likely pretty misleading...

##### Share on other sites

One thing I noticed: you're using _scprintf and snprintf, but you're passing those functions the va_list you have. I think you want to be using _vscprintf and vsnprintf.

Also, I know this isn't your main problem, but: I think MSVC understands and properly handles the special case where you call vsnprintf/snprintf with a destination buffer of NULL and a length of 0, so you may be able to avoid the #ifdef WIN32 stuff. (EDIT: just tested _snprintf(NULL, 0, fmt, etc) on MSVC 2010 and it returned the proper length).

Edited by Samith

##### Share on other sites

Thanks for the answer. Just out of curiosity - did you test it with a direct variadic input or the va_list enumerator? It does work for me in the former case, but I can't get it working with va_list - eg when SPRINT() is a proxy function with variadic input.

PS: VC doesn't have snprintf(), hence my using _snprintf() (as commented out). Click me.

Edited by irreversible

##### Share on other sites

Thanks for the answer. Just out of curiosity - did you test it with a direct variadic input or the va_list enumerator? It does work for me in the former case, but I can't get it working with va_list - eg when SPRINT() is a proxy function with variadic input.

PS: VC doesn't have snprintf(), hence my using _snprintf() (as commented out). Click me.

Hmm, when I wrote the above post I only tested _snprintf. But just now I tested vsnprintf and it all worked. Here's my test code:

void test_vsnprintf(const char *fmt, ...)
{
va_list arg;
va_start(arg, fmt);
const int len = vsnprintf(NULL, 0, fmt, arg);
printf("len: %d\n", len);
va_end(arg);
}

int main(int argc, const char *argv[])
{
test_vsnprintf("hello %d %s", 10, "fun times");		// prints "len: 18", as expected/desired

return 0;
}


##### Share on other sites

Hm - I actually feel a bit silly for not having tried that myself. Strange though that Google and the dozen or so sites I checked didn't point this out to me. Also strange - that the functions I did try didn't work, even though they seem to explicitly claim to do so.

In any case - help much appreciated!

1. 1
2. 2
3. 3
4. 4
frob
11
5. 5

• 11
• 16
• 13
• 20
• 12
• ### Forum Statistics

• Total Topics
632175
• Total Posts
3004583

×