cout, cerr, Clog ของ iostream header ใน c ++ ต่างกันอย่างไร? เมื่อใดควรใช้อันไหน?


104

ฉันพยายามค้นคว้าความแตกต่างระหว่างcout, cerrและclogบนอินเทอร์เน็ต แต่ไม่สามารถหาคำตอบที่สมบูรณ์ ฉันยังไม่ชัดเจนว่าจะใช้เมื่อใด ใครช่วยอธิบายให้ฉันฟังผ่านโปรแกรมง่ายๆและอธิบายสถานการณ์ที่สมบูรณ์แบบว่าเมื่อใดควรใช้อันไหน

ผมเข้าเยี่ยมชมเว็บไซต์นี้ซึ่งแสดงให้เห็นโปรแกรมขนาดเล็กบนcerrและแต่การส่งออกที่ได้รับมากกว่านอกจากนี้ยังสามารถรับใช้clog coutฉันสับสนกับการใช้งานของแต่ละคน


6
แต่ละคนมีสตรีมที่คอมพิวเตอร์รู้จักstdout, stdin(สำหรับcin) และstderrใช้โดยค่าเริ่มต้น ฉันเชื่อว่าclogเป็นเพียงcerrการเปลี่ยนแปลงบัฟเฟอร์
chris

คำตอบ:


53

stdoutและstderrเป็นสตรีมที่แตกต่างกันแม้ว่าทั้งคู่จะอ้างถึงคอนโซลเอาต์พุตตามค่าเริ่มต้น การเปลี่ยนเส้นทาง (ท่อ) หนึ่งในนั้น (เช่นprogram.exe >out.txt) จะไม่ส่งผลกระทบต่ออีก

โดยทั่วไปstdoutควรใช้สำหรับเอาต์พุตของโปรแกรมจริงในขณะที่ควรพิมพ์ข้อมูลและข้อความแสดงข้อผิดพลาดทั้งหมดstderrเพื่อที่ว่าหากผู้ใช้เปลี่ยนเส้นทางเอาต์พุตไปยังไฟล์ข้อความข้อมูลจะยังคงพิมพ์อยู่บนหน้าจอไม่ใช่ไปยังไฟล์เอาต์พุต


133

โดยทั่วไปคุณจะใช้std::coutสำหรับเอาต์พุตปกติstd::cerrสำหรับข้อผิดพลาดและstd::clogสำหรับ "การบันทึก" (ซึ่งอาจหมายถึงอะไรก็ได้ที่คุณต้องการ)

ความแตกต่างที่สำคัญstd::cerrคือไม่ได้บัฟเฟอร์เหมือนอีกสองตัว


ในความสัมพันธ์กับ C เก่าstdoutและstderr, std::coutสอดคล้องกับstdoutในขณะที่std::cerrและstd::clogทั้งสอดคล้องกับstderr(ยกเว้นว่าstd::clogมีบัฟเฟอร์)


ฉันได้อ่านแล้วว่าclogยังส่งออกไปยังcerr. จากนั้นคุณจะเลือกอันไหน? ถ้าclogปกติสำหรับ "การบันทึก" เหตุใดฉันจึงต้องการไปที่สตรีมข้อผิดพลาด บันทึกดูเหมือน "บันทึกปกติ" (aka cout) มากกว่าข้อผิดพลาด
void.pointer

@ void.pointer ที่ผมกล่าวในคำตอบของฉันทั้งสองcerrและclogใช้มาตรฐาน "ข้อผิดพลาด" การส่งออก แต่มีบัฟเฟอร์ซึ่งอาจจะเป็นเหตุผลที่มันดูเหมือนว่าเหมือนclog coutจะเลือกข้อผิดพลาดใด ขึ้นอยู่กับฉันเดาด้วยเหตุผลมากกว่าที่ฉันสามารถระบุได้และจะต้องมีการตัดสินใจเป็นกรณี ๆ ไป
เพื่อนโปรแกรมเมอร์บางคน

3
"บัฟเฟอร์" หมายความว่าอย่างไร
ธรรมดา

6
@simplename Output ไม่ได้เขียนโดยตรง แต่จะถูกเก็บไว้ในบัฟเฟอร์จนกว่าบัฟเฟอร์จะถูกล้างล้างการส่งออกไปยังไฟล์หรือเทอร์มินัลช้าในอดีต (เทอร์มินัลหรือคอนโซลยังคงทำงานช้า) การเขียนอักขระทีละอักขระจะไม่ได้ผลการเขียนจำนวนไบต์จะมีประสิทธิภาพมากกว่ามาก
เพื่อนโปรแกรมเมอร์บางคน

17

Standard output stream (cout): coutเป็นอินสแตนซ์ของostreamคลาส coutใช้เพื่อสร้างเอาต์พุตบนอุปกรณ์เอาต์พุตมาตรฐานซึ่งโดยปกติจะเป็นหน้าจอแสดงผล ข้อมูลที่จำเป็นในการแสดงบนหน้าจอจะถูกแทรกในสตรีมเอาต์พุตมาตรฐาน ( cout) โดยใช้ตัวดำเนินการแทรก ( <<)

Un-buffered standard error stream (cerr): cerrเป็นสตรีมข้อผิดพลาดมาตรฐานที่ใช้เพื่อส่งออกข้อผิดพลาด นี่เป็นตัวอย่างของostreamชั้นเรียนด้วย ในฐานะที่cerrเป็นปฏิปักษ์ต่อบัฟเฟอร์จึงถูกนำมาใช้เมื่อเราต้องการที่จะแสดงข้อผิดพลาดทันที ไม่มีบัฟเฟอร์ใด ๆ ในการจัดเก็บข้อความแสดงข้อผิดพลาดและแสดงในภายหลัง

สตรีมข้อผิดพลาดมาตรฐานบัฟเฟอร์ (การอุดตัน):นี่เป็นตัวอย่างของostreamคลาสและใช้เพื่อแสดงข้อผิดพลาด แต่ต่างจากcerrข้อผิดพลาดที่ถูกแทรกลงในบัฟเฟอร์ก่อนและจะถูกเก็บไว้ในบัฟเฟอร์จนกว่าจะไม่เต็ม

อ่านเพิ่มเติม : basic-input-output-c


2
until it is not fully filled.- ไม่ควรพูดuntil it IS fully filled?
Gabriel Staples

11

ความแตกต่างของ 3 สตรีมนี้คือการบัฟเฟอร์

  1. ด้วย cerr เอาต์พุตจะล้างออก
    • ทันที (เนื่องจาก cerr ไม่ใช้บัฟเฟอร์)
  2. ด้วยการอุดตันเอาต์พุตจะล้างออก
    • หลังจากคุณเสร็จสิ้นฟังก์ชันปัจจุบันของคุณ
    • เรียกใช้ฟังก์ชันล้างอย่างชัดเจน
  3. ด้วย cout เอาต์พุตจะล้างออก
    • หลังจากที่คุณโทรไปยังสตรีมเอาต์พุตใด ๆ (cout, cerr, Clog)
    • หลังจากคุณเสร็จสิ้นฟังก์ชันปัจจุบันของคุณ
    • เรียกใช้ฟังก์ชันล้างอย่างชัดเจน

โปรดตรวจสอบรหัสต่อไปนี้และเรียกใช้ DEBUG ผ่าน 3 บรรทัด: f (std :: Clog), f (std :: cerr), f (std :: out) จากนั้นเปิดไฟล์เอาต์พุต 3 ไฟล์เพื่อดูว่าเกิดอะไรขึ้น คุณสามารถสลับ 3 บรรทัดนี้เพื่อดูว่าจะเกิดอะไรขึ้น

#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";
}

10
  • ใช้coutสำหรับเอาต์พุตมาตรฐาน
  • ใช้cerrเพื่อแสดงข้อผิดพลาด
  • ใช้การอุดตันสำหรับการบันทึก

6
ผิด cerr ช้ากว่า cout เพราะไม่ใช่บัฟเฟอร์! เช่นเดียวกับ write vs printf
陳力

5

จากเอกสารมาตรฐาน C ++ 17 แบบร่าง:

30.4.3 วัตถุสตรีมแคบ [narrow.stream.objects]

istream cin;

1 อ็อบเจ็กต์cinควบคุมอินพุตจากบัฟเฟอร์สตรีมที่เกี่ยวข้องกับอ็อบเจ็กต์stdinประกาศใน<cstdio>(30.11.1)

2 หลังจากที่วัตถุที่cinจะเริ่มต้นได้ผลตอบแทนcin.tie() &coutสถานะเป็นอย่างอื่นเหมือนกับที่กำหนดไว้สำหรับbasic_ios<char>::init(30.5.5.2)

ostream cout;

3 อ็อบเจ็กต์coutควบคุมเอาต์พุตไปยังสตรีมบัฟเฟอร์ที่เกี่ยวข้องกับอ็อบเจ็กต์stdoutประกาศใน<cstdio>(30.11.1)

ostream cerr;

4 อ็อบเจ็กต์cerrควบคุมเอาต์พุตไปยังสตรีมบัฟเฟอร์ที่เกี่ยวข้องกับอ็อบเจ็กต์stderrประกาศใน<cstdio>(30.11.1)

5 หลังจากที่วัตถุที่cerrจะเริ่มต้น, cerr.flags() & unitbufไม่ใช่ศูนย์และผลตอบแทนcerr.tie() &coutสถานะเป็นอย่างอื่นเหมือนกับที่กำหนดไว้สำหรับbasic_ios<char>::init(30.5.5.2)

ostream clog;

6 อ็อบเจ็กต์clogควบคุมเอาต์พุตไปยังสตรีมบัฟเฟอร์ที่เกี่ยวข้องกับอ็อบเจ็กต์stderrประกาศใน<cstdio>(30.11.1)

อภิปรายผล...

coutเขียนถึงstdout; cerrและclogถึงstderr

Standard Out ( stdout) มีไว้เพื่อรับเอาต์พุตที่ไม่ใช่ข้อผิดพลาดและไม่ใช่การวินิจฉัยจากโปรแกรมเช่นเอาต์พุตจากการประมวลผลที่สำเร็จซึ่งสามารถแสดงต่อผู้ใช้ปลายทางหรือสตรีมไปยังขั้นตอนการประมวลผลเพิ่มเติม

ข้อผิดพลาดมาตรฐาน ( stderr) มีไว้สำหรับเอาต์พุตการวินิจฉัยเช่นคำเตือนและข้อความแสดงข้อผิดพลาดที่ระบุว่าโปรแกรมไม่ได้หรืออาจไม่ได้สร้างเอาต์พุตที่ผู้ใช้อาจคาดหวัง อินพุตนี้อาจแสดงต่อผู้ใช้แม้ว่าข้อมูลเอาต์พุตจะถูกส่งไปยังขั้นตอนการประมวลผลเพิ่มเติม

cinและcerrเชื่อมโยงกับcout

ทั้งสองล้างcoutก่อนที่จะจัดการการดำเนินงาน I / O ด้วยตนเอง สิ่งนี้ทำให้มั่นใจได้ว่าพร้อมต์ที่ส่งถึงcoutจะมองเห็นได้ก่อนที่โปรแกรมจะบล็อกเพื่ออ่านอินพุตจากcinและเอาต์พุตก่อนหน้านี้จะcoutถูกล้างก่อนที่จะเขียนข้อผิดพลาดผ่านcerrซึ่งจะเก็บข้อความตามลำดับเวลาของการสร้างเมื่อทั้งสองถูกส่งไปยังเทอร์มินัล / ไฟล์ / เดียวกัน ฯลฯ ..

สิ่งนี้ตรงกันข้ามกับclog- ถ้าคุณเขียนที่นั่นมันจะไม่ถูกบัฟเฟอร์และไม่ผูกติดกับอะไรเลยดังนั้นมันจะบัฟเฟอร์การบันทึกในปริมาณที่เหมาะสมก่อนที่จะล้างออก สิ่งนี้ให้ปริมาณงานสูงสุดของข้อความ แต่หมายความว่าข้อความอาจไม่สามารถมองเห็นได้อย่างรวดเร็วสำหรับผู้บริโภคที่อ่านเทอร์มินัลหรือกำหนดส่วนท้ายของบันทึก


1

ทั้งศาลและเกิดการอุดตันเป็น buffered แต่cerrคือยกเลิกบัฟเฟอร์และทั้งหมดของเหล่านี้จะถูกกำหนดไว้ล่วงหน้าวัตถุซึ่งเป็นกรณีของ ostream ระดับ การใช้งานพื้นฐานของทั้งสามนี้คือcoutใช้สำหรับอินพุตมาตรฐานในขณะที่ clogและcerrเพื่อแสดงข้อผิดพลาด ประเด็นหลักที่ทำไมcerrไม่บัฟเฟอร์อาจเป็นเพราะสมมติว่าคุณมีเอาต์พุตหลายตัวในบัฟเฟอร์และมีการกล่าวถึงข้อผิดพลาดในโค้ดจากนั้นคุณต้องแสดงข้อผิดพลาดนั้นทันทีซึ่งสามารถทำได้โดยcerrอย่างมีประสิทธิภาพ

กรุณาแก้ไขฉันถ้าฉันผิด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.