CのsprintfをC++/STLで実現する

今まで避けて通ってきた道でしたが、C++でsprintfを使うには少々違和感があった。
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() );
}
2008-02-14 | コメント:2件
Previous Page | Next Page