Приостановка и перезапуск вывода терминала

То, что я пытаюсь сделать, это заставить терминал распечатать строку, сделать паузу, а затем записать эту строку. Однако происходит то, что программа просто выводит окончательный результат, даже не показывая первую строку.

Я думал, что смогу использовать sleep для этого, но это не работает. Почему бы и нет?

#include <stdio.h>
#include <unistd.h>

int main(void){

    char message[] = "Hello there";
    int messageLength = sizeof(message);
    int i;

    printf("Hello, Dave.");
    sleep(2);
    for(i = 0; i < messageLength; i++)
        printf("\b");
    printf("Anyone there?\n");

    return 0;

}

Обновленная версия благодаря ответам:

#include <stdio.h>
#include <unistd.h>
#include <time.h>

void twprint(char* output, int outputLength, struct timespec* delay);
void twbackspace(int length, struct timespec* delay);

int main(void){

    char message1[] = "Hello, Dave.";
    char message2[] = "Are you there, Dave?";
    char message3[] = "I heard you talking in the pod.";
    char message4[] = "Dave?";
    struct timespec duration = { .tv_sec = 0, .tv_nsec = (100 * 1000 * 1000) }; 
    /* ^ .tv_nsec = one hundred million nanoseconds */

    twprint(message1, sizeof(message1)/sizeof(char), &duration);
    sleep(2);
    twbackspace(sizeof(message1)/sizeof(char), &duration);

    twprint(message2, sizeof(message2)/sizeof(char), &duration);
    sleep(2);
    twbackspace(sizeof(message2)/sizeof(char), &duration);

    twprint(message3, sizeof(message3)/sizeof(char), &duration);
    sleep(2);
    twbackspace(sizeof(message3)/sizeof(char), &duration);

    sleep(2);
    duration.tv_nsec *= 5;
    twprint(message4, sizeof(message4)/sizeof(char), &duration);

    printf("\n");

    return 0;

}

void twprint(char* output, int outputLength, struct timespec* delay){

    int i;
    struct timespec remaining; /* dummy parameter */

    for(i = 0; i < outputLength; i++){
        printf("%c", output[i]);
        fflush(stdout);
        nanosleep(delay, &remaining);
    }

}

void twbackspace(int length, struct timespec* delay){

    int i;
    struct timespec remaining; /* dummy parameter */

    for(i = 0; i < length; i++){
        printf("\b \b");
        fflush(stdout);
        nanosleep(delay, &remaining);
    }
}

person Chris Middleton    schedule 17.03.2014    source источник
comment
Вы стираете свое сообщение в цикле for, вот почему.   -  person γηράσκω δ' αεί πο    schedule 17.03.2014
comment
@valter, ты не говоришь? :D   -  person Chris Middleton    schedule 17.03.2014
comment
@valter Вот почему что? Вы хоть читали, что хочет сделать ОП?   -  person Jim Balter    schedule 17.03.2014
comment
@JimBalter Но он меня рассмешил.   -  person Chris Middleton    schedule 17.03.2014


Ответы (2)


Вывод printf буферизуется и не будет выводиться на консоль до тех пор, пока буфер не заполнится, вы не напечатаете новую строку или не вызовете fflush(stdout). Пытаться:

...
printf("Hello, Dave.");
fflush(stdout);
sleep(2);
...

Википедия предоставляет хорошее объяснение стандартных потоков и их поведения в отношении буферизации.

person Liam M    schedule 17.03.2014

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

printf("Hello, Dave.");
fflush(stdout);

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

person rici    schedule 17.03.2014
comment
@AmadeusDrZaius stderr, как следует из названия, предназначен для вывода ошибок; Писать в него что-либо, кроме диагностики, я бы посчитал ошибкой. По умолчанию он не буферизован, чтобы гарантировать, что вывод ошибок будет виден немедленно (и даже в случае сбоя программы). Однако и stdout, и stderr могут быть перенаправлены на устройство или в файл, а не на терминал, и их буферизация может быть изменена (см. man7.org/linux/man-pages/man3/setbuf.3.html). Для вывода, который обязательно должен быть отправлен на терминал, вы можете использовать /dev/tty (stackoverflow.com/questions/8514735/) - person Jim Balter; 17.03.2014