C++에서 endl vs \n 성능 차이 알아보기

2025. 2. 12. 07:19코딩 도구/기술 & 정보 글 (Tech & Knowledge)

반응형

C++에서 endl vs \n 성능 차이

어느날 처럼 코테 문제를 풀다가 예전에 코테에서는 절대 endl 을 쓰지 마라 라는 말이 기억이나서  출력 부분에서 아무것도 없이 vs \n vs endl 이렇게 출력 시간을 비교해보았는데 시간 차이가 났다. 

위에서 부터 endl, \n, x 순서이다. 

 

특히 코딩 테스트나 대량의 데이터를 출력할 때 endl\n의 차이가 실행 속도에 큰 영향을 줄 수 있다고 해서 한번 알아보았다. 

 

endl\n의 차이

C++에서 줄바꿈을 출력하는 방법은 대표적으로 다음 두 가지가 있다:

  1. std::endl: 줄바꿈(\n)을 수행한 후, 출력 버퍼를 즉시 비운다(flush).
  2. '\n': 단순히 줄바꿈을 수행하며, 출력 버퍼를 유지한다.

즉, std::endl줄바꿈 후 강제로 버퍼를 비우기 때문에 출력 성능이 떨어질 수 있다. 반면 \n은 버퍼링을 유지하면서 출력하므로 성능이 훨씬 좋다.

예제 코드: endl vs \n 성능 비교

다음은 endl\n을 사용했을 때의 실행 속도를 비교하는 코드이다.

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    int n = 100000;

    // endl 사용 (비효율적)
    auto start1 = chrono::high_resolution_clock::now();
    for (int i = 0; i < n; i++) {
        cout << i << endl; // 느림
    }
    auto end1 = chrono::high_resolution_clock::now();
    cout << "Time with endl: " 
         << chrono::duration<double>(end1 - start1).count() << "s\n";

    // '\n' 사용 (효율적)
    auto start2 = chrono::high_resolution_clock::now();
    for (int i = 0; i < n; i++) {
        cout << i << '\n'; // 빠름
    }
    auto end2 = chrono::high_resolution_clock::now();
    cout << "Time with \\n: " 
         << chrono::duration<double>(end2 - start2).count() << "s\n";

    return 0;
}

실행 결과 (출력 속도 비교)

끝부분 숫자만 출력되고, endl 테스트 결과가 나오지 않는 현상이 발생한 이유는 출력 버퍼링과 플러싱(flushing) 문제 때문인 것 같다.

 

원인은 아래와 같다.

원인 분석

  1. 출력 버퍼링 영향
    • std::cout은 기본적으로 내부 버퍼(buffer)를 사용해서 출력을 관리함.
    • cout << i << '\n';은 버퍼를 채운 후 한 번에 출력하는 반면, cout << i << endl;은 매번 flush가 발생하여 즉시 출력됨.
    • 따라서 터미널이 모든 출력을 바로 처리하지 못하고 마지막 일부 출력만 보임.
  2. endl 테스트 결과가 사라진 이유
    • cout << "Time with endl: " ...이 실행되었을 때, 버퍼가 아직 비워지지 않아서 endl 테스트 결과가 출력되지 않았을 가능성이 큼.
    • 특히, 터미널에서는 버퍼링된 출력이 한 번에 표시되거나 특정 크기에 도달할 때만 출력되므로 endl 테스트 부분이 사라질 수 있음.
  3. 터미널의 출력 제한 문제
    • 터미널(콘솔)에는 출력 속도 제한이 있음.
    • 100,000줄을 터미널에서 한꺼번에 처리하는 경우, 운영체제가 일부 출력 내용을 버릴 수 있음.
    • 그래서 마지막 몇 천 개의 출력만 보이는 것처럼 보일 수 있음.

 

해결 방법

  1. 출력을 터미널이 아니라 파일로 저장해서 정확한 결과 확인
    • 터미널 대신 파일(ofstream)에 저장하면 운영체제의 터미널 출력 제한을 피할 수 있음.
  2. 출력 버퍼를 강제 플러시(flush()) 해서 올바른 순서로 출력 확인
    • cout.flush();를 추가해서 강제로 출력 내용을 내보내면 출력이 사라지는 문제를 방지할 수 있음.

수정된 코드 (정확한 비교 가능)

#include <bits/stdc++.h>
using namespace std;
using namespace chrono;

const int n = 100000; // 테스트 반복 횟수

void testWithEndl(ofstream &file) {
    auto start = high_resolution_clock::now();
    for (int i = 0; i < n; i++) {
        file << i << endl; // endl 사용 (매번 flush)
    }
    auto end = high_resolution_clock::now();
    cout << "Time with endl: " << duration<double>(end - start).count() << "s\n";
    cout.flush(); // 강제 플러시 (터미널에서 사라지는 문제 해결)
}

void testWithNewline(ofstream &file) {
    auto start = high_resolution_clock::now();
    for (int i = 0; i < n; i++) {
        file << i << '\n'; // '\n' 사용 (버퍼링됨)
    }
    auto end = high_resolution_clock::now();
    cout << "Time with \\n: " << duration<double>(end - start).count() << "s\n";
    cout.flush(); // 강제 플러시
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    ofstream file1("output_endl.txt");
    ofstream file2("output_newline.txt");

    cout << "Running tests...\n";
    cout.flush(); // 플러시 추가

    // endl 테스트
    testWithEndl(file1);
    file1.close();

    // '\n' 테스트
    testWithNewline(file2);
    file2.close();

    cout << "Tests completed.\n";
    cout.flush(); // 결과가 사라지는 문제 방지

    return 0;
}

 

 

코딩 테스트에서는 endl을 절대 사용하지 말자!

코딩 테스트에서는 실행 속도가 중요한데, endl을 사용하면 불필요한 버퍼 flush로 인해 실행 시간이 길어진다. 따라서 항상 \n을 사용하여 출력 속도를 최적화하는 것이 중요하다.

 

cout.tie(0);을 활용한 입출력 최적화

입출력을 더 빠르게 하고 싶다면, 다음과 같이 cin.tie(0);을 설정하면 된다.

ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);

이렇게 하면 cincout이 독립적으로 작동하여 입출력 속도를 더욱 향상할 수 있다.

반응형