Jaka jest różnica między cout, cerr, clog of iostream header w c ++? Kiedy użyć którego?

103

Próbowałem bada różnicę pomiędzy cout, cerroraz clogw Internecie, ale nie mógł znaleźć idealne odpowiedź. Nadal nie wiem, kiedy którego użyć. Czy ktoś może mi wyjaśnić za pomocą prostych programów i zilustrować idealną sytuację, kiedy należy użyć którego?

Odwiedziłem tę stronę, która pokazuje mały program na cerri clog, ale dane wyjściowe tam uzyskane można również uzyskać za pomocą cout. Więc jestem zdezorientowany co do dokładnego zastosowania każdego z nich.

Arlene Batada
źródło
6
Każdy z nich ma strumień rozpoznawany przez komputer stdout, stdin(dla cin) i stderrużywa go domyślnie. Uważam, że clogjest to tylko cerrzmiana buforująca.
chris

Odpowiedzi:

51

stdouti stderrsą różnymi strumieniami, mimo że oba odnoszą się domyślnie do wyjścia konsoli. Przekierowanie (potokowanie) jednego z nich (np. program.exe >out.txt) Nie wpłynie na inne.

Generalnie, stdoutpowinno być używane do rzeczywistego wyjścia programu, podczas gdy wszystkie informacje i komunikaty o błędach powinny być drukowane stderr, tak aby jeśli użytkownik przekierował wyjście do pliku, komunikaty informacyjne nadal były drukowane na ekranie, a nie do pliku wyjściowego.

riv
źródło
132

Zwykle używasz std::coutdo normalnego wyjścia, std::cerrdo błędów i std::clogdo "rejestrowania" (co może oznaczać cokolwiek chcesz, żeby oznaczało).

Główną różnicą jest to, że std::cerrnie jest buforowany tak jak dwa pozostałe.


W odniesieniu do starego C stdouti stderr, std::coutodpowiada na stdout, podczas std::cerri std::clogobu odpowiada na stderr(oprócz tego, że std::clogjest buforowany).

Jakiś koleś programista
źródło
Czytałem, że clogrównież wysyła do cerr. Na tej podstawie, którą z nich wybierzesz? Jeśli clogjest to normalne dla „rejestrowania”, dlaczego miałbym chcieć, aby to przechodziło do strumienia błędów? Dzienniki bardziej przypominają „normalne dzienniki” (inaczej cout) niż błędy.
void.pointer
@ void.pointer Jak powiedziałem w mojej odpowiedzi, oba cerri clogużywają standardowego wyjścia "błędu", ale clogsą buforowane, co może być przyczyną bardziej podobnego działania cout. Który wybrać do wyświetlania błędów? To zależy, jak sądzę, z większej liczby powodów, niż potrafię wymienić, i trzeba to rozstrzygać w zależności od przypadku.
Jakiś programista,
3
co masz na myśli mówiąc „buforowany”?
simplename
6
Wyjście @simplename nie jest napisane wprost, jest przechowywany w buforze , dopóki bufor jest zaczerwieniona . Wyjście do pliku lub terminala jest historycznie powolne (terminale lub konsole są nadal powolne), zapis znak po znaku jest nieefektywny, zapisywanie fragmentu bajtów jest znacznie bardziej efektywne.
Jakiś programista
16

Standardowy strumień wyjściowy (cout): cout jest instancją ostreamklasy. coutsłuży do generowania danych wyjściowych na standardowym urządzeniu wyjściowym, którym jest zwykle ekran wyświetlacza. Dane potrzebne do wyświetlenia na ekranie są wstawiane do standardowego strumienia wyjściowego ( cout) za pomocą operatora wstawiania ( <<).

Niesbuforowany standardowy strumień błędów (cerr): cerr jest to standardowy strumień błędów używany do wyświetlania błędów. Jest to również instancja ostreamklasy. Ponieważ cerrjest niebuforowany , jest używany, gdy musimy natychmiast wyświetlić komunikat o błędzie. Nie ma żadnego bufora do przechowywania komunikatu o błędzie i wyświetlania go później.

Buforowany standardowy strumień błędów (zatkanie): jest to również wystąpienie ostreamklasy i służy do wyświetlania błędów, ale w przeciwieństwie cerrdo błędu jest najpierw wstawiany do buforu i przechowywany w buforze, dopóki nie zostanie całkowicie wypełniony.

Dalsza lektura: podstawowe-wejście-wyjście-c

roottraveller
źródło
until it is not fully filled.- czy to nie powinno mówić until it IS fully filled?
Gabriel Staples
11

Różnica między tymi 3 strumieniami polega na buforowaniu.

  1. Z cerr wyjście jest spłukiwane
    • natychmiast (ponieważ cerr nie używa bufora).
  2. W przypadku zatkania wyjście przepływa
    • po zakończeniu bieżącej funkcji.
    • jawnie wywołaj funkcję flush.
  3. Z cout, wyjście się spłukuje
    • po wywołaniu dowolnych strumieni wyjściowych (cout, cerr, clog).
    • po zakończeniu bieżącej funkcji.
    • jawnie wywołaj funkcję flush.

Sprawdź poniższy kod i uruchom DEBUG w 3 liniach: f (std :: clog), f (std :: cerr), f (std :: out), a następnie otwórz 3 pliki wyjściowe, aby zobaczyć, co się stało. Możesz zamienić te 3 linie, aby zobaczyć, co się stanie.

#include <iostream>
#include <fstream>
#include <string>

void f(std::ostream &os)
{
    std::cin.clear(); // clear EOF flags
    std::cin.seekg(0, std::cin.beg); // seek to begin

    std::string line;
    while(std::getline(std::cin, line))   //input from the file in.txt
        os << line << "\n";   //output to the file out.txt
}

void test()
{
    std::ifstream in("in.txt");
    std::ofstream out("out.txt"), err("err.txt"), log("log.txt");
    std::streambuf *cinbuf = std::cin.rdbuf(), *coutbuf = std::cout.rdbuf(), *cerrbuf = std::cerr.rdbuf(),
                    *clogbuf = std::clog.rdbuf();

    std::cin.rdbuf(in.rdbuf()); //redirect std::cin to in.txt!
    std::cout.rdbuf(out.rdbuf()); //redirect std::cout to out.txt!
    std::cerr.rdbuf(err.rdbuf());
    std::clog.rdbuf(log.rdbuf());


    f(std::clog);
    f(std::cerr);
    f(std::cout);

    std::cin.rdbuf(cinbuf);
    std::cout.rdbuf(coutbuf);
    std::cerr.rdbuf(cerrbuf);
    std::clog.rdbuf(clogbuf);
}

int main()
{
    test();
    std::cout << "123";
}
Duc-Viet Ha
źródło
10
  • Użyj cout jako standardowego wyjścia.
  • Użyj cerr aby wyświetlić błędy.
  • Użyj zatkania do logowania.
David Vargas
źródło
6
Źle, cerr jest wolniejszy niż cout z powodu braku bufora! Podobnie jak write vs printf
陳 力
4

Z wersji roboczej standardowego dokumentu C ++ 17:

30.4.3 Obiekty o wąskim strumieniu [narrow.stream.objects]

istream cin;

1 Obiekt cinsteruje wejściem z bufora strumieniowego związanego z obiektem stdin, zadeklarowanym w <cstdio>(30.11.1).

2 Po cinzainicjowaniu obiektu cin.tie()zwraca &cout. basic_ios<char>::initPoza tym jego stan jest taki sam, jak wymagany w (30.5.5.2).

ostream cout;

3 Obiekt coutsteruje wyjściem do bufora strumieniowego związanego z obiektem stdout, zadeklarowanym w <cstdio>(30.11.1).

ostream cerr;

4 Obiekt cerrsteruje wyjściem do bufora strumieniowego związanego z obiektem stderr, zadeklarowanym w<cstdio> (30.11.1).

5 Po cerrzainicjowaniu obiektu cerr.flags() & unitbufjest niezerowa i cerr.tie()zwraca &cout. basic_ios<char>::initPoza tym jego stan jest taki sam, jak wymagany w (30.5.5.2).

ostream clog;

6 Obiekt clogsteruje wyjściem do bufora strumieniowego związanego z obiektem stderr, zadeklarowanym w <cstdio>(30.11.1).

Dyskusja...

coutpisze do stdout; cerri clogdostderr

Standardowe wyjście (stdout ) ma na celu odbieranie z programu bezbłędnych, niediagnostycznych danych wyjściowych, takich jak dane wyjściowe z pomyślnego przetwarzania, które mogą być wyświetlane użytkownikowi końcowemu lub przesyłane strumieniowo do dalszego etapu przetwarzania.

Standard Error ( stderr) jest przeznaczony do diagnostyki danych wyjściowych, takich jak ostrzeżenia i komunikaty o błędach, które wskazują, że program nie wygenerował lub mógł nie wygenerować danych wyjściowych, których użytkownik mógłby się spodziewać. Te dane wejściowe mogą być wyświetlane użytkownikowi końcowemu, nawet jeśli dane wyjściowe są przesyłane potokiem do dalszego etapu przetwarzania.

cini cerrsą przywiązanicout

Obaj opróżniają się coutprzed samodzielną obsługą operacji we / wy. Zapewnia to, że podpowiedzi wysyłane do coutsą widoczne przed blokami programu, z których mają odczytać dane wejściowe cin, oraz że wcześniejsze wyjście do coutjest opróżniane przed zapisaniem błędu cerr, co utrzymuje komunikaty w chronologicznej kolejności ich generowania, gdy oba są kierowane do tego samego terminala / pliku / itp..

Kontrastuje to z clog- jeśli tam napiszesz, nie będzie buforowany i nie będzie z niczym powiązany, więc przed opróżnieniem będzie buforował przyzwoite ilości logowania. Zapewnia to największą przepustowość komunikatów, ale oznacza, że ​​komunikaty mogą nie być szybko widoczne dla potencjalnego konsumenta czytającego terminal lub śledzącego dziennik.

Tony Delroy
źródło
1

Zarówno cout, jak i clog są buforowane, ale cerr nie jest buforowany, a wszystkie z nich są predefiniowanymi obiektami, które są instancjami klasy ostream. Podstawowym zastosowaniem tych trzech jest cout jest używane do standardowego wejścia, podczas gdy clog i cerr jest używane do wyświetlania błędów. Głównym powodem, dla którego cerr nie jest buforowany, może być to, że przypuśćmy, że masz kilka wyjść w buforze i w kodzie jest wymieniony wyjątek błędu, a następnie musisz natychmiast wyświetlić ten błąd, co może być skutecznie wykonane przez cerr .

Proszę, popraw mnie jeśli się mylę.

Kashif Faraz Shamsi
źródło