Dlaczego printf nie spłukuje się po wywołaniu, chyba że znak nowej linii znajduje się w łańcuchu formatu?

Dlaczego printf nie jest spłukiwana po wywołaniu, chyba że znak nowej linii znajduje się w łańcuchu formatu? Czy to zachowanie POSIX? Jak Mogę mieć printf natychmiast spłukać za każdym razem?

 444
Author: K DawG, 2009-11-11

9 answers

Strumień stdout jest buforowany, więc wyświetli tylko to, co jest w buforze, gdy osiągnie nową linię (lub gdy zostanie tak poproszony). Masz kilka opcji do wydrukowania od razu:

Drukuj na stderr zamiast za pomocą fprintf:

fprintf(stderr, "I will be printed immediately");

Flush stdout gdy potrzebujesz go użyć fflush:

printf("Buffered, will be flushed");
fflush(stdout); // Will now print everything in the stdout buffer

Edit: z poniższego komentarza Andy ' ego Rossa można również wyłączyć buforowanie na stdout za pomocą setbuf:

setbuf(stdout, NULL);
 573
Author: Rudd Zwolinski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-11 20:24:36

Nie, to nie zachowanie POSIX, to zachowanie ISO (cóż, to to zachowanie POSIX, ale tylko o ile jest zgodne z ISO).

Standardowe wyjście jest buforowane liniowo, jeśli można je wykryć w odniesieniu do urządzenia interaktywnego, w przeciwnym razie jest w pełni buforowane. Są więc sytuacje, w których printf nie będzie spłukiwać, nawet jeśli otrzyma nową linię do wysłania, takie jak:

myprog >myfile.txt

To ma sens dla wydajności, ponieważ, jeśli jesteś interakcji z użytkownikiem, prawdopodobnie chcą zobaczyć każdy Kolejka Jeśli wysyłasz dane wyjściowe do pliku, najprawdopodobniej nie ma Użytkownika na drugim końcu(choć nie jest to niemożliwe, może on śledzić plik). Teraz możesz argumentować, że użytkownik chce zobaczyć każdą postać, ale są z tym dwa problemy.

Po pierwsze, nie jest zbyt wydajny. Po drugie, pierwotny mandat ANSI C polegał przede wszystkim na kodyfikacji istniejących zachowań, a nie wymyślaniu nowych zachowań, a te decyzje zostały podjęte na długo przed rozpoczęciem procesu przez ANSI. Nawet ISO w dzisiejszych czasach postępuje bardzo ostrożnie przy zmianie istniejących zasad w normach.

Jak sobie z tym poradzić, jeśli fflush (stdout) po każdym wywołaniu wyjściowym, które chcesz natychmiast zobaczyć, to rozwiąże problem.

Alternatywnie, możesz użyć setvbuf przed uruchomieniem na stdout, aby ustawić go na unbuffered i nie będziesz musiał martwić się o dodanie wszystkich linii fflush do kodu:

setvbuf (stdout, NULL, _IONBF, BUFSIZ);

Po prostu pamiętaj może to mieć znaczny wpływ na wydajność, jeśli wysyłasz wyjście do pliku. Należy również pamiętać, że wsparcie dla tego jest zdefiniowane w implementacji, a nie gwarantowane przez standard.

Sekcja ISO C99 7.19.3/3 jest odpowiednim bitem:

Gdy strumień jest niebuforowany , znaki powinny pojawić się ze źródła lub w miejscu docelowym tak szybko, jak to możliwe. W przeciwnym razie znaki mogą być gromadzone i przesyłane do lub ze środowiska hosta jako blok.

Gdy strumień jest w pełni buforowany, znaki są przeznaczone do przesyłania do lub ze środowiska hosta jako blok, gdy bufor jest wypełniony.

Gdy strumień jest buforem linii , znaki są przeznaczone do przesyłania do lub ze środowiska hosta jako blok, gdy napotkany jest znak nowej linii.

Ponadto znaki są przeznaczone do przesyłania jako blok do środowiska hosta, gdy bufor jest wypełniony, gdy dane wejściowe są wymagane w strumieniu niebuforowanym lub gdy dane wejściowe są wymagane w strumieniu buforowanym, który wymaga transmisji znaków ze środowiska hosta.

Wsparcie dla tych cech jest zdefiniowane w implementacji i może być wpływane za pomocą funkcji setbuf i setvbuf.

 103
Author: paxdiablo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-17 03:58:08

Prawdopodobnie tak jest z powodu wydajności i dlatego, że jeśli masz wiele programów piszących do jednego TTY, w ten sposób nie masz znaków na linii przeplatanych. Więc jeśli program A i B są wysyłane, Zwykle otrzymujesz:

program A output
program B output
program B output
program A output
program B output
To śmierdzi, ale jest lepsze niż
proprogrgraam m AB  ououtputputt
prproogrgram amB A  ououtputtput
program B output

Zauważ, że nie jest nawet zagwarantowane spłukiwanie na nowej linii, więc powinieneś spłukać wyraźnie, jeśli spłukiwanie ma dla Ciebie znaczenie.

 22
Author: Southern Hospitality,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-11 17:54:06

Aby natychmiast spłukać wywołanie fflush(stdout) LUB fflush(NULL) (NULL czyli spłukać wszystko).

 19
Author: Aaron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-25 01:10:09

Uwaga: biblioteki uruchomieniowe Microsoft nie obsługują buforowania linii, więc printf("will print immediatelly to terminal"):

Http://msdn.microsoft.com/en-us/library/86cebhfs.aspx

 11
Author: Renato,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-14 20:36:47

Stdout jest buforowany, więc zostanie wyświetlony dopiero po wydrukowaniu nowej linii.

Aby uzyskać natychmiastowe wyjście, albo:

  1. Drukuj na stderr.
  2. aby stdout nie był buforowany.
 10
Author: Douglas Leeder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-11 16:25:08

Domyślnie, stdout jest buforowany w linii, stderr nie jest buforowany, a plik jest całkowicie buforowany.

 10
Author: woso,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-29 02:02:19

Możesz zamiast tego użyć fprintf na stderr, który nie jest buforowany. Albo możesz spłukać stdout, kiedy chcesz. Możesz też ustawić stdout na unbuffered.

 8
Author: Rasmus Kaj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-11 16:26:49

Użyj setbuf(stdout, NULL);, aby wyłączyć buforowanie.

 6
Author: dnahc araknayirp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-31 03:22:52