STLのstringクラス を使うようになり、『やっぱstrstreamか』と思った時期もあったが、最近、Rubyでプログラムを組む機会があり、あっさりとsprintfがサポートしているのを見て、stringクラスを返すsprinfのようなものがあってもよいなと思い直し作成した。
/**********************************************************************
CのsprintfをC++/STLで実現する
使い方
std::string str = cformat( "%d:%s", intvalue, charpointer);
試したコンパイル環境
VC++ .NET 2003 / WINDOWS XP Professional 64 bit edition.
GCC C++ 3.3.6 / glibc 2.3.4 / Vine Linux 4.2
**********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <vector>
#include <string>
#include <stdexcept>
#ifdef _WIN32
#define vsnprintf _vsnprintf
#endif
std::string cformat( char *format, ...)
{
int bufsize = 1024; // 適当なサイズ
std::vector<char> buff(bufsize);
va_list args;
// 適当なバッファサイズで先ずは、vsnprintfを試す。
// 出力がバッファサイズ以上の場合、VC++ .NET 2003の場合は -1、
// glibc2.1以降は、書き込みに必要なサイズを返す。
va_start(args, format);
int vssize = vsnprintf( &buff[0], bufsize, format, args);
va_end(args);
// vsnprintfが成功した場合終了する。
if ( vssize >= 0 && vssize < bufsize ) {
buff.resize(vssize);
return std::string( buff.begin(), buff.end() );
}
#ifdef _WIN32
// VC++ .NET 2003 書き込みに必要なサイズを取得する。
va_start(args, format);
vssize = _vscprintf( format, args);
va_end(args);
#endif
if ( vssize < 0 ) throw std::runtime_error(format);
// サイズを再割り当てし、再度試す
buff.resize(vssize + 1);
va_start(args, format);
vssize = vsnprintf( &buff[0], vssize + 1, format, args);
va_end(args);
if ( vssize < 0 ) throw std::runtime_error(format);
buff.resize(vssize);
return std::string( buff.begin(), buff.end() );
}