Как преобразовать вывод warn() в строку?

Я использую нестандартную функцию warn() (предоставленную BSD) для вывода сообщения об ошибке, если файл не может быть открыт, например:

std::string path = get_path() ;
std::ifstream file(path) ;
if (file.is_open()) { /* do something */ }
else {
    warn("%s", path.c_str()) ;
    // uses errno to figure out what the error was and outputs it nicely along with the filename
}

Это все очень хорошо для вывода, но что, если я хочу использовать всю строку где-то еще, в дополнение к ее печати? Функции warn(), похоже, не имеют формы, которая записывает ошибку в строку. Я пытался свернуть свой собственный, но по сравнению с ним он кажется ужасно громоздким (кроме того, что я не получил имя программы):

this->foo((boost::format("%s: %s") % path % strerror(errno)).str()) ;

Итак, как мне получить вывод warn() в виде строки?


person Blacklight Shining    schedule 26.02.2013    source источник
comment
Откуда warn? Это, конечно, не стандартная функция C++, поэтому, возможно, документация API, из которого вы ее используете, поможет больше...   -  person PlasmaHH    schedule 26.02.2013
comment
@PlasmaHH Это стандартная функция C?   -  person Blacklight Shining    schedule 26.02.2013
comment
@BlacklightShining: Это не так.   -  person PlasmaHH    schedule 26.02.2013
comment
@BlacklightShining: Это, гм, нет.   -  person Lightness Races in Orbit    schedule 26.02.2013
comment
@PlasmaHH На его справочной странице написано, что он находится в стандартной библиотеке C…   -  person Blacklight Shining    schedule 26.02.2013
comment
@BlacklightShining: В каком разделе и параграфе стандарта это упоминается?   -  person PlasmaHH    schedule 26.02.2013
comment
@BlacklightShining: на какую страницу руководства вы смотрите?   -  person Lightness Races in Orbit    schedule 26.02.2013
comment
@LightnessRacesinOrbit err(3) — около дюжины функций имеют дело с форматированными сообщениями об ошибках.   -  person Blacklight Shining    schedule 26.02.2013
comment
@PlasmaHH Я не мог тебе сказать. o.o Если есть лучший способ печатать сообщения об ошибках, я готов переключиться…   -  person Blacklight Shining    schedule 26.02.2013
comment
@BlacklightShining Эти функции являются нестандартными расширениями BSD.   -  person Joseph Mansfield    schedule 26.02.2013
comment
@BlacklightShining: когда вы утверждаете, что они стандартные C, вам лучше это сделать. Их много, в зависимости от ваших точных требований, если вам нужны строки формата, то мне кажется хорошей идеей обернуть boost::format в вариативные шаблоны.   -  person PlasmaHH    schedule 26.02.2013
comment
@BlacklightShining Я не вижу упоминания стандартной библиотеки C в err(3). Похоже, это функция BSD. В любом случае, ответ то, что вы уже написали.   -  person Lightness Races in Orbit    schedule 26.02.2013


Ответы (3)


warn помещает свой вывод в стандартный вывод ошибок. Таким образом, вам придется создать механизм для перенаправления стандартного вывода ошибок в место, которое вы можете прочитать обратно в строку. Самый простой способ может состоять в том, чтобы перенаправить стандартную ошибку в файл, а затем прочитать файл обратно в виде строки. Вы можете, например, попытаться использовать dup2() для этого (как объяснено в ответе на этот вопрос).

Тем не менее, упаковка вашей собственной версии warn, вероятно, является лучшим выбором. Однако вы можете рассмотреть функцию C vsnprintf() для ее реализации. На этот вопрос есть ответы, в которых используются как boost::format, так и vsnprintf().

person jxh    schedule 26.02.2013

Вы правы, аналога sprintf (то есть гипотетической функции swarn) не существует.

Ваш подход кажется жизнеспособным.

person Lightness Races in Orbit    schedule 26.02.2013

Может показаться, что ваши вращения приводят к результату, подобному:

path + ": " +  strerror(errno);

Можно предположить, что «имя программы», которое она включает, вероятно, просто argv[0], так что вы могли бы, по-видимому, создать примерно эквивалент вашего warn, который просто возвращает std::string с чем-то в этом общем порядке:

std::string warn_s(std::string const &path) { 
    char *pname = strrchr(argv[0], '/');
    if (pname == NULL)
        pname = argv[0];
    return path + pname + ":  " + strerror(errno);
}

Основная трудность здесь заключается в том, что argv является локальным для main, поэтому вам, вероятно, потребуется либо сохранить его в доступном месте в main, либо использовать какой-то нестандартный механизм для повторного извлечения этих данных в вашей функции.

К сожалению, документация для warn, которую я смог найти, была достаточно плохой, поэтому, вероятно, потребуется немного тестирования/проб и ошибок, если вы хотите точно воспроизвести его вывод.

person Jerry Coffin    schedule 26.02.2013