понедельник, 5 июля 2010 г.

Форматированная строка в std::string

Не нравится мне пользоваться STL потоками для форматирования строк в C++. Не нравится, и все. ИМХО, потоки STL удобны для чего угодно, но не для этого. Особенно если это Debug print с кучей отладочной инфы.
Куда краше сишные конструкции с форматированным выводом. Для программистов, которые любят и знают C, запись printf("%d %d %d\n", a,b,c) более приятна и читабельна чем cout << a << b << c << endl.

Как то раз я написал такой класс и использую теперь во всех своих проектах:

#pragma once

#include <string>
#include <stdlib.h>
#include <iostream>
#include <stdarg.h>

class FormattedString : public std::string
{
public:
static std::string Format (const std::string format, ...);

private:
static std::string FormatArgumentsList(const std::string format, va_list arguments);

static const int StartBufferSize = 64;
static const int BufferSizeIncrement = 256;
};


#include "FormattedString.h"

using namespace std;

#include <memory>
#include <stdio.h>

#ifdef ANSI
# include <stdarg.h>
int average( int first, ... );
#else
# include <varargs.h>
int average( va_list );
#endif

string FormattedString::Format(const std::string format, ...)
{
va_list arguments;
va_start(arguments, format);

string resultString = FormatArgumentsList(format, arguments);

va_end(arguments);
return resultString;
}

string FormattedString::FormatArgumentsList(const string format, va_list arguments)
{
int bufferSize = StartBufferSize ;
std::auto_ptr<char> buffer;

do
{
buffer.reset(new char[bufferSize]);

#ifdef _MSC_VER
int result = _vsnprintf_s(buffer.get(), bufferSize, bufferSize-1, format.c_str(), arguments);
#else
int result = vsnprintf(buffer.get(),bufferSize-1,format.c_str(),arguments);
#endif //_MSC_VER

if (result < 0)
{
bufferSize += BufferSizeIncrement;
continue;
}
break;
} while(true);

return buffer.get();
}


Пользоваться этим очень просто:

std::string myString = FormattedString::Format("%d (%s) %5.2f", 10, "Hello world", 3.14f);
// или
std::cout << FormattedString::Format("HEX: %X",0xABCDEF) << std::endl;


С компиляторами, отличными от Visual Studio, библиотечная функция vsnprintf небезопасна. Поэтому, во избежании уязвимостей, рекомендую использовать класс только для статической или отладочной печати, либо хотя бы проверять аргументы перед отправкой в FormattedString::Format.

Комментариев нет:

Отправить комментарий