"Как отформатировать выводимую строку?" — каждый из нас, я уверен, задавался таким вопросом. Не секрет, что сейчас к старому доброму sprintf'у добавилось множество современных выводов на экран:
iostream, stringstream, boost. Про их сравнение хорошо рассказывает
известная статья.
Printf хорош своими скоростью, простотой и наглядностью, но небезопасен: нет ни проверки типов аргументов, ни размера буфера. Правда, первая проблема уже решена современными компиляторами или утилитами типа Lint. Проблема размера буфера решается в ф-ции _snprintf, но даже она не может предотвратить, скажем, передачу некорректных указателей.
Но решение есть! Это — исключения, штатный механизм C++. Просто взгляите на этот код:
void safeSprintf(char *Dst, int DstSize, char *Format, ...)
{
va_list marker;
va_start(marker, Format);
try
{
_vsnprintf(Dst, DstSize, Format, marker); // Главное действо
}
catch(...)
{
WriteLog("criticals.log", "PARSER Exception in safeSprintf!");
try // сбойную строку с форматированием - в лог
{
char TmpBuf[STDSIZE];
strncpy(TmpBuf, Format, STDSIZE);
TmpBuf[STDSIZE-1] = 0; // т.к. strncpy не добавляет NULL при переполнении
prsReplaceChar(TmpBuf, '%', '_'); // убираем форматирование
WriteLog("criticals.log", TmpBuf);
strcpy(Dst, "ERROR! PARSER Exception in safeSprintf!");
}
catch(...)
{
WriteLog("criticals.log", "PARSER Exception while processing exception!");
}
}// catch
va_end(marker);
}
Механизм исключений убирает главную проблему sprintf — недостаток надежности. Такая редакция ф-ции держит даже конструкции типа
safeSprintf(NULL, 1024*1024, NULL, NULL);
— без выпадений, но с записью сбойных операторов в лог для ошибок!
Станет ли такой safeSprintf новой жизнью для sprintf?