Всегда ли printf очищает буфер при встрече с новой строкой? - PullRequest
10 голосов
/ 08 марта 2011

Моя машина работает под управлением Ubuntu 10.10, и я использую стандартную библиотеку gnu C. У меня сложилось впечатление, что printf очищает буфер, если в строке формата описана новая строка, однако следующий код неоднократно, казалось, нарушал эту тенденцию. Может кто-нибудь уточнить, почему буфер не очищается.

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>

int main()
{
    int rc;
    close(1);
    close(2);
    printf("HI 1\n");
    fprintf(stderr, "ERROR\n");

    open("newfile.txt", O_WRONLY | O_CREAT | O_TRUNC, 0600);
    printf("WHAT?\n");
    fprintf(stderr, "I SAID ERROR\n");

    rc = fork();

    if (rc == 0)
    {
        printf("SAY AGAIN?\n");
        fprintf(stderr, "ERROR ERROR\n");
    }
    else
    {
        wait(NULL);
    }

    printf("BYE\n");
    fprintf(stderr, "HI 2\n");

    return 0;
}

Содержимое newfile.txt после запуска этой программы выглядит следующим образом.

HI 1
WHAT?
SAY AGAIN?
BYE
HI 1
WHAT?
BYE

Ответы [ 3 ]

26 голосов
/ 08 марта 2011

Нет, стандарт гласит, что stdout изначально полностью буферизован, если устройство вывода может быть определено как неинтерактивное.

Это означает, что если вы перенаправите stdout в файлна новой строке не вспыхнет.Если вы хотите попробовать принудительно сделать его буферизированным строкой, используйте setbuf или setvbuf.

Соответствующая часть C99, 7.19.3 Files, paragraph 7, сообщает:

При запуске программы три текстовых потока предопределены и не требуют явного открытия - стандартный ввод (для чтения обычного ввода), стандартный вывод (для записи обычного вывода) и стандартная ошибка (для записи диагностического вывода).При первоначальном открытии стандартный поток ошибок не полностью буферизован;стандартные входные и стандартные выходные потоки полностью буферизуются тогда и только тогда, когда можно определить, что поток не относится к интерактивному устройству.

Просто имейте в виду раздел 5.1.2.3/6:

То, что составляет интерактивное устройство, определяется реализацией.

2 голосов
/ 08 марта 2011

Это сбрасывается , если устройство вывода является интерактивным одним, например, терминалом .

Вам необходимо очистить буфер вывода, если устройство вывода может быть определено как неинтерактивное , например, файл . Новая строка не делает это автоматически.

Подробнее см. ответ Паксдиабло .

0 голосов
/ 08 марта 2011

У вас странное чувство юмора. :)

int main()
{
    int rc;
    close(1);
    close(2);
    printf("HI 1\n");
    fprintf(stderr, "ERROR\n");

Вы закрываете файловые дескрипторы, используемые для stdout и stderr, а затем сразу же пытаетесь использовать потоки C stdout и stderr FILE. Не очень хорошая идея, я не уверен, что будет делать библиотека C, чтобы сообщить вам об ошибке , но сбой был бы приемлемой возможностью .

Помимо этой странности, когда вы используете для записи стандартные функции потока ввода-вывода, буферизация частично зависит от места назначения. Если вы пишете в терминал, то обычным поведением является буферизация строки. Если вы пишете в канал, файл или сокет, то обычным поведением является буферизация блоков. Вы можете изменить режим буферизации с помощью функции setvbuf(3). Полная информация о поведении буферизации находится на странице руководства.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...