Когда std:: fprintf (stderr,...) завершается с ошибкой, не работает ли операция или может написать немного до сбоя?

У меня есть программа на С++ 11, которая использует std::fprintf для записи в stderr в качестве информации журнала и отладки. Я знаю, что fprintf может терпеть неудачу и возвращать отрицательное значение, но я не могу определить, является ли операция атомарной (если она не работает, не имеет никакого эффекта) или может написать некоторую часть текста, а затем сбой (или любой другой побочный эффект).

Функция, использующая fprintf, выглядит следующим образом:

void writeToConsole (std::string const &message)
{
    std::fprintf(stderr, "%s\n", message.c_str());
}

Я разрабатываю, используя Clang и GCC в Linux (пока), но мой вопрос больше о стандарте, поэтому...

Вопрос:

Если std::fprintf не удается, все еще возможно, что некоторые символы были записаны в stderr? Является ли это поведение стандартом C/С++ или определяется реализацией?

Более того, если std::fprintf не удается, я должен прервать выполнение программы или продолжить выполнение без каких-либо побочных эффектов (кроме невозможности записи в stderr)?

Ответ 1

Имейте в виду, что семейство функций printf (почти всегда) в конечном итоге превращается в вызов функции write(2) (или другой подобный эквивалент OS/Implementation с низким уровнем). Эта функция может быть частично успешной. Если записано хотя бы один байт, функция завершается успешно (если ошибка обнаружения базового адресата не может быть обнаружена, например, прерывание обработчиком сигнала), и оно вернет количество фактически записанных байтов:

Количество записанных байтов может быть меньше, чем count, если, например, недостаточно места на базовом физическом носителе или встречается ограничение ресурса RLIMIT_FSIZE (см. setrlimit (2)), или вызов был прерывается обработчиком сигнала после того, как записано меньше байтов подсчета. [...]

Информацию о частичной записи см. в write(2), например, в http://man7.org/linux/man-pages/man2/write.2.html. Значения для errno или других эффектов частичной записи могут зависеть от выходного носителя (или того, что представляет собой файловый дескриптор - файл с отображением памяти, обычный файл и т.д.), А также конкретная reason для отказа. Например, ENOMEM, EIO, EDQUOT - все возможности.

Также см. связанную страницу man для дополнительной информации об атомарности в отношении нескольких потоков.

Ваш другой вопрос:

Более того, если std:: printf терпит неудачу, я должен прервать выполнение программы или продолжить выполнение без каких-либо побочных эффектов (кроме невозможности записи в stderr)?

Это действительно зависит от вашей программы.

Ответ 2

Для fprintf стандарт С++ 11 возвращается к C99, поскольку он является частью стандартной библиотеки C, а в черновом стандарте C99 говорится следующее:

Функция fprintf возвращает количество переданных символов или отрицательное значение, если произошла ошибка вывода или кодирования.

но на самом деле не указывает, означает ли ошибка, что символ не передан или нет, так что это будет зависеть от реализации.

Для POSIX совместимых систем, которые в этом случае должны охватывать Linux, ссылка для fprintf говорит:

После успешного завершения функции fprintf() и printf() возвращают количество переданных байтов.

[...]

Если возникла ошибка вывода, эти функции должны возвращать отрицательное значение.

В списке есть несколько ошибок, которые могут привести к частичному выводу, например:

[ENOMEM]

Доступно недостаточно места для хранения.

Указывает, указывает ли ошибка, что вы должны выйти из приложения, зависит ли ваше приложение от другого механизма регистрации, кроме stderr? Имеет ли ваше приложение юридические требования, которые требуют, чтобы все регистрировалось или журналы были исключительно информационными и т.д.