views:

166

answers:

5

I'm writing a small proof-of-concept console program with Visual Studio 2008 and I wanted it to output colored text for readability. For ease of coding I also wanted to make a quick printf-replacement, something where I could write like this:

MyPrintf(L"Some text \1[bright red]goes here\1[default]. %d", 21);

This will be useful because I also build and pass strings around in some places so my strings will be able to contain formatting info.

However I hit a wall against wsprintf because I can't find a function that would allow me to find out the required buffer size before passing it to the function. I could, of course, allocate 1MB just-to-be-sure, but that wouldn't be pretty and I'd rather leave that as a backup solution if I can't find a better way.

Also, alternatively I'm considering using std::wstring (I'm actually more of a C guy with little C++ experience so I find plain-old-char-arrays easier for now), but that doesn't have anything like wsprintf where you could build a string with values replaced in them.

So... what should I do?

+3  A: 

I'd go for a C++ stringstream. It's not as compact as sprintf but it will give you the functionality you want.

Sean
Could you give some examples of usage? As I said, I'm not very strong in C++ and all those templates make my head spin. I can't really make out how it's supposed to work from the documentation. :(
Vilx-
AshleysBrain has provided an example which covers your post. I'll avoid duplicating his example.
Sean
A: 

Using std::wstring seems like a good solution if you plan on passing strings between your objects - it handles the size and has a nice c_str method that will give you the array of wide chars.

The additional benefit is that you can pass it by reference instead of by pointer.

When you need the actuall string just use c_str method:

wprintf(L"string %s recieved!", myWString.c_str());
Dror Helper
Fine, but what about when I want something like `"Opened connection to %s on port %hd"` ?
Vilx-
just use c_str - See above
Dror Helper
+2  A: 

If you can afford using boost, you could consider boost::format. It would give you the flexibility of std::strings, and formatting features of sprintf. It is fairly different from C-style, but is also fairly easy to use. Here's an example.

Dmitry
+3  A: 

You want _snwprintf. That function takes a buffer size, and if the buffer isn't big enough, just double the size of the buffer and try again. To keep from having to do multiple _snwprintf calls each time, keep track of what the buffer size was that you ended up using last time, and always start there. You'll make a few excess calls here and there, and you'll waste a bit of ram now and then, but it works great, and can't over-run anything.

Michael Kohne
In GCC there's a similar function called snprintf. Instead of using that or the one you suggest which is MS specific, it's better to use a portable replacement like this: http://www.ijs.si/software/snprintf/
Manuel
As Manuel stated - it should be made clear that Microsoft's `_snprintf()` differs from the standard `snprintf()` in significant ways and should be avoided in preference to one that behaves in a more standard fashion if possible. Unfortunately, it looks like MS haven't fixed this problem in VS2010... I prefer Holger Weiss' implementation since the license is very non-restrictive (I'm not sure how the Frontier Artistic license applies to my whole program if I incorporate Mark Martinec's `snprintf()` from http://www.ijs.si into my program).
Michael Burr
I wanted to give an answer that didn't require adding libraries, so I went with the solution local to the OP. I personally also prefer the standard snprintf because it's return value is much more useful, but I hate telling folks to drag in external libraries for one function.
Michael Kohne
+4  A: 

Your question is tagged C++, in which case I'd say std::wstringstream is the way to go. Example:

#include <sstream>

void func()
{
    // ...

    std::wstringstream ss;  // the string stream

    // like cout, you can add strings and numbers by operator<<
    ss << L"Some text \1[bright red]goes here\1[default]. " << 21;

    // function takes a C-style const wchar_t* string
    some_c_function(ss.str().c_str()); // convert to std::wstring then const wchar_t*
    // note: lifetime of the returned pointer probably temporary
    // you may need a permanent std::wstring to return the c_str() from
    // if you need it for longer.

    // ...
}
AshleysBrain