Может ли printf (или fprintf или dprintf) вернуть ("успешно") меньше (но не отрицательно) числа "всех байтов"?

В руководстве сказано, что

После успешного возврата эти функции [printf, dprintf и т. Д.] Возвращают количество напечатанных символов.

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

Функция dprintf работает с дескриптором файла. Аналогично функции записи, для которой в руководстве упоминается, что

В случае успеха возвращается количество записанных байтов (ноль означает, что ничего не было записано). Не является ошибкой, если это число меньше числа запрошенных байтов;

Так что, если я хочу написать строку полностью, я должен приложить n = write() в то время как цикл. Должен ли я сделать то же самое в случае dprintf или printf?

4 ответа

Мое понимание документации таково, что dprintf либо потерпит неудачу, либо выведет весь вывод. Но я согласен, что это какая-то серая зона (и я не очень хорошо понимаю); Я предполагаю, что частичный вывод является своего рода ошибкой (поэтому возвращает отрицательный размер).

Вот реализация http://musl-libc.org/:

В stdio / dprintf.c dprintf функция просто вызывает vdprintf

Но в stdio / vdprintf.c у вас просто есть:

static size_t wrap_write(FILE *f, const unsigned char *buf, size_t len)
{
    return __stdio_write(f, buf, len);
}

int vdprintf(int fd, const char *restrict fmt, va_list ap)
{
    FILE f = {
        .fd = fd, .lbf = EOF, .write = wrap_write,
        .buf = (void *)fmt, .buf_size = 0,
        .lock = -1
    };
    return vfprintf(&f, fmt, ap);
}

Так dprintf возвращает размер как vfprintf (а также fprintf....)

Однако, если вы действительно обеспокоены, вам лучше использовать snprintf или же asprintf выводить в некоторый буфер памяти и явно использовать write(2) для этого буфера.

Посмотрите в stdio / __stdio_write.c реализацию __stdio_write (он использует writev(2) с вектором из двух блоков данных в цикле).

Другими словами, мне часто было бы все равно; но если вам действительно нужно быть уверенным, что каждый байт записан так, как вы ожидаете (например, если дескриптор файла - это некий сокет HTTP), я бы предложил явно буферизовать (например, вызвав snprintf и / или asprintf), затем используйте явную запись (2).

PS. Вы можете проверить исходный код вашей конкретной стандартной библиотеки C, предоставляя dprintf ; для GNU glibc смотрите, в частности, libio / iovdprintf.c

С stdio возвращать количество частично записанных байтов не имеет особого смысла, потому что функции stdio работают с (более или менее) глобальным буфером, состояние которого вам неизвестно и перетаскивается из предыдущих вызовов.

Если бы функции stdio позволяли вам работать с этим, возвращаемые значения ошибок должны были бы быть более сложными, поскольку они должны были бы не только сообщать, сколько символов было или не было выведено, но также и был ли сбой до вашего последнего ввода где-то в буфер, или в середине вашего последнего ввода, и если да, то сколько последнего ввода было буферизовано.

Теоретически d-функции могут легко подсчитать количество частично записанных символов, но POSIX указывает, что они должны отражать функции stdio, и поэтому они дают вам только еще одно неопределенное отрицательное значение при ошибке.

Если вам нужно больше контроля, вы можете использовать функции более низкого уровня.

Что касается printf()Это вполне понятно.

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

Отрицательное значение возвращается, если произошла ошибка. В этом случае может быть напечатано 0 или более символов. Количество невозможно узнать через стандартную библиотеку.

Если возвращаемое значение не является отрицательным, то это число, отправленное stdout,

поскольку stdout часто буферизуется, что может не совпадать с номером, полученным на выходе устройства при выводе printf(), следить printf() с fflush(stdout)

int r1 = printf(....);
int r2 = fflush(stdout);
if (r1 < 0 || r2 != 0) Handle_Failure();

Для лучшего контроля, "печать" в буфер и использовать putchar() или различные нестандартные функции.

Я держу пари, что нет. (После просмотра источника obfuscated - printf.) Таким образом, любое неотрицательное возвращаемое значение означает, что printf был полностью успешным (достигнут конец строки формата, все было передано в буферы ядра).
Но некоторые (подлинные) люди должны это подтвердить.

Другие вопросы по тегам