I am trying to write a variable argument function on SUN solaris. According to MSDN, the _vscprintf function that I'm using on windows should work on unix as ANSI is listed.
_vscprintf<stdio.h>ANSI, Win 98, Win Me, Win NT, Win 2000, Win XP
However, including stdio.h doesn't seem to help. Is this function located in some other header file on unix?

>should work on unix as ANSI is listed.
_vscprintf isn't a standard C function. It's a Microsoft extension that is unlikely to work on Unix.

So their indication of ANSI means nothing? Bastards.

Any alternative way to find out the length of the string so that I can properly allocate memory?

This is the current function (errorMessage is a class member string)

DHException (const char * exceptText, ...)
 
{
 
 
 
va_list args;
 
int len;
 
char * buffer;
 
va_start( args, exceptText );
 
len = _vscprintf( exceptText, args )+ 1; // terminating '\0'
 
buffer = new char[ len * sizeof(char)];
 
vsprintf( buffer, exceptText, args );
 
errorMessage = buffer;
 
delete [] buffer;
 
}

>So their indication of ANSI means nothing?
They're probably talking about naming conventions, not strict standard conformance.

>Any alternative way to find out the length of the string so that I can properly allocate memory?
Not easily. You would have to resize the buffer as you go. But since this is C++, why not just use a std::string? :)

>buffer = new char[ len * sizeof(char)];
sizeof(char) is guaranteed to be 1, so you can safely say:

buffer = new char[len];

>errorMessage = buffer;
That looks suspicious. If errorMessage is a pointer to char, you'll have problems when the memory for buffer is released.

>}
Don't forget to use va_end.

errorMessage is of type 'string'.

How do I use std::string for this? I didn't think there was a function to handle the va_arg using string.

Also, wouldn't it need to be :
buffer = new char[len +1];
to handle the null terminator?
I have added va_end( args); per your suggestion

> I didn't think there was a function to handle the va_arg using string.
Nevermind, you probably don't want to do it that way, and it was silly of me to suggest it. Let's try this again:

>Any alternative way to find out the length of the string so that I can properly allocate memory?
A safe alternative is to use vfprintf to write to a temporary file, and use its return value the same way you're using _vscprintf:

len = vfprintf( tmpfile(), exceptText, args ) + 1;

Of course, since tmpfile can return NULL, you shouldn't use it as a direct argument like that. vfprintf and tmpfile are standard functions, so they will always be available. If you have performance issues then there are less convenient methods.

>Also, wouldn't it need to be :
>buffer = new char[len +1];
No, you did that when initializing len.

(Yes, my bad on the +1)

In your opinion, would it better to use the tmpfile(), or to establish a pre-defined maximum log length and therefore have theoretically enough buffer available to handle the log?


(Do I need to do an fclose on tmpfile() ?)

>or to establish a pre-defined maximum log length and therefore have theoretically enough buffer
That doesn't sound safe if you still use a variadic function. You can add error handling, but then you could end up truncating error messages. I would say (without further knowledge of your application) that tmpfile is the best solution without forcing you to do a lot of extra work.

>(Do I need to do an fclose on tmpfile() ?)
You don't need to as it will be closed automagically when the program terminates. However, it's never a bad idea for functions to clean up after themselves, and if the function is called often then you could hit the limit of allowable open file streams. So it would be a good idea.

My 2 cents: In Builder6 the function vsnprintf (or vsnwprintf) do report the needed length when the input buffer size is set to zero.

This article has been dead for over six months. Start a new discussion instead.