Что не так с этим заказом на печать - PullRequest
1 голос
/ 29 сентября 2011

посмотрите на этот код:

 #include<stdio.h>
 #include <unistd.h>
    int main()
    {
            int pipefd[2],n;
            char buf[100];
            if(pipe(pipefd)<0)
                    printf("Pipe error");
            printf("\nRead fd:%d write fd:%d\n",pipefd[0],pipefd[1]);
            if(write(pipefd[1],"Hello Dude!\n",12)!=12)
                    printf("Write error");
            if((n=read(pipefd[0],buf,sizeof(buf)))<=0)
                    printf("Read error");
            write(1,buf,n);
            return 0;
    }

Я ожидаю, что printf напечатает Read fd и напишет fd до того, как Hello Dude будет считан из канала. Но это не тот случай ... см. здесь . Когда я попробовал ту же программу в нашей компьютерной лаборатории колледжа, мой результат был

Read fd:3 write fd:4
Hello Dude!

также мало кто из наших друзей заметил, что изменение оператора printf, содержащего большее количество символов \n, изменило порядок вывода ... например .. printf("\nRead fd:%d\n write fd:%d\n",pipefd[0],pipefd[1]); означало, что Read fd печатается, а затем сообщение Hello Dude! тогда пишется fd записи. Что это за поведение? Примечание. В нашей лаборатории используется сервер Linux, на котором мы запускаем терминалы, хотя я не помню версию компилятора.

Ответы [ 4 ]

5 голосов
/ 29 сентября 2011

Это потому, что printf к стандартному выводу поток буферизован, но write к стандартному выводу дескриптор файла нет.

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

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

Когда вы запускаете его в интерактивном режиме, сброспроисходит до write, потому что printf встречается с \n и автоматически сбрасывается.

Однако, когда вы запускаете его иначе (например, перенаправляя вывод в файл или в онлайн-компилятор / исполнитель, где онвероятно, сделал бы то же самое, чтобы захватить данные для представления), сброс происходит после write (потому что printf не сбрасывает после каждой строки).

На самом деле,вам не нужны все эти каналы, чтобы увидеть это в действии, согласно следующей программе:

    #include <stdio.h>
    #include <unistd.h>
    int main (void) {
        printf ("Hello\n");
        write (1, "Goodbye\n", 8);
        return 0;
    }

Когда я выполняю myprog ; echo === ; myprog >myprog.out ; cat myprog.out, я получаю:

Hello
Goodbye
===
Goodbye
Hello

и вы можете увидеть разницу между разными типами буферизации.

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

setvbuf (stdin, NULL, _IOLBF, BUFSIZ);

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

4 голосов
/ 29 сентября 2011

Вы не должны смешивать вызовы с write и printf в дескрипторе одного файла.Измените write на fwrite.

Функции, которые используют FILE, буферизуются.Функции, которые используют файловые дескрипторы, не являются.Вот почему вы можете получить смешанный заказ.

Вы также можете попробовать позвонить fflush до write.

2 голосов
/ 29 сентября 2011

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

С помощью fflush() вы можете контролировать это поведение.

1 голос
/ 29 сентября 2011

Что происходит, так это то, что printf пишет в стандартный вывод буферизованным способом - строка сохраняется в буфере перед выводом - в то время как «запись» позже записывает в стандартный вывод без буферизации. Это может привести к тому, что вывод команды «write» появится первым, если буфер из printf будет очищен только позже.

Вы можете явно сбросить, используя fflush() - но еще лучше не смешивать буферизованные и небуферизованные записи в один и тот же вывод. Введите man printf, man fflush, man fwrite и т. Д. На своем терминале, чтобы узнать больше о том, что именно эти команды делают.

...