C++의 cout와 C의 printf 성능 비교 분석

업데이트 20210927: 일부 테스트는 NOI Linux 2.0 가상 환경에서 진행되었습니다. 테스트 환경은 다음과 같습니다:

CPU: i3 1115G4 @ 1C2T

RAM: 2G

컴파일 옵션: g++ test.cpp -o test -std=c++14

0. 테스트 환경:

컴퓨터 사양:

CPU: i5 7500 RAM: 8G 운영체제: Win7 64비트 테스트 디스크: intel 256G SSD 최적화 없음, C++98 사용, GCC 4.9.2 64비트

1. 문자열 출력 비교 (개행 없음)

코드:

// 테스트 1: 문자열 출력에서의 cout와 printf 비교
#include <iostream>
#include <cstdio>
#include <chrono>
using namespace std;
const int ITERATIONS = 10000000; // 1천만 번 반복
chrono::high_resolution_clock::time_point start_time, cout_time, printf_time;

int main(){
    freopen("output.txt","w",stdout);
    start_time = chrono::high_resolution_clock::now();
    
    for(int counter = 1; counter <= ITERATIONS; ++counter){
        cout << "PERFORMANCE_TEST";
    }
    
    cout_time = chrono::high_resolution_clock::now();
    
    for(int counter = 1; counter <= ITERATIONS; ++counter){
        printf("PERFORMANCE_TEST");
    }
    
    printf_time = chrono::high_resolution_clock::now();
    
    freopen("results.txt","w",stdout);
    
    auto cout_duration = chrono::duration_cast<chrono::duration<double>>(cout_time - start_time);
    auto printf_duration = chrono::duration_cast<chrono::duration<double>>(printf_time - cout_time);
    
    cout << "cout   : " << cout_duration.count() << "s" << endl;
    cout << "printf : " << printf_duration.count() << "s" << endl;
    
    return 0;
}

결과:

cout   : 0.617s
printf : 21.279s

2. 정수 출력 비교 (개행 없음)

코드:

// 테스트 2: 정수 출력에서의 cout와 printf 비교
#include <iostream>
#include <cstdio>
#include <chrono>
using namespace std;
const int ITERATIONS = 10000000; // 1천만 번 반복
chrono::high_resolution_clock::time_point start_time, cout_time, printf_time;

int main(){
    freopen("output.txt","w",stdout);
    start_time = chrono::high_resolution_clock::now();
    
    for(int counter = 1; counter <= ITERATIONS; ++counter){
        cout << counter;
    }
    
    cout_time = chrono::high_resolution_clock::now();
    
    for(int counter = 1; counter <= ITERATIONS; ++counter){
        printf("%d", counter);
    }
    
    printf_time = chrono::high_resolution_clock::now();
    
    freopen("results.txt","w",stdout);
    
    auto cout_duration = chrono::duration_cast<chrono::duration<double>>(cout_time - start_time);
    auto printf_duration = chrono::duration_cast<chrono::duration<double>>(printf_time - cout_time);
    
    cout << "cout   : " << cout_duration.count() << "s" << endl;
    cout << "printf : " << printf_duration.count() << "s" << endl;
    
    return 0;
}

결과:

cout   : 0.723s
printf : 21.012s

업데이트: NOI Linux 환경에서의 결과:

cout   : 0.415719s
printf : 0.458123s

cout   : 0.391156s
printf : 0.467886s

cout   : 0.421311s
printf : 0.547006s

3. long long 정수 출력 비교 (개행 없음)

코드:

// 테스트 3: long long 정수 출력에서의 cout와 printf 비교
#include <iostream>
#include <cstdio>
#include <chrono>
using namespace std;
const int ITERATIONS = 10000000; // 1천만 번 반복
chrono::high_resolution_clock::time_point start_time, cout_time, printf_time;

int main(){
    freopen("output.txt","w",stdout);
    start_time = chrono::high_resolution_clock::now();
    
    for(int counter = 1; counter <= ITERATIONS; ++counter){
        cout << static_cast<long long>(counter) * ITERATIONS;
    }
    
    cout_time = chrono::high_resolution_clock::now();
    
    for(int counter = 1; counter <= ITERATIONS; ++counter){
        printf("%lld", static_cast<long long>(counter) * ITERATIONS);
    }
    
    printf_time = chrono::high_resolution_clock::now();
    
    freopen("results.txt","w",stdout);
    
    auto cout_duration = chrono::duration_cast<chrono::duration<double>>(cout_time - start_time);
    auto printf_duration = chrono::duration_cast<chrono::duration<double>>(printf_time - cout_time);
    
    cout << "cout   : " << cout_duration.count() << "s" << endl;
    cout << "printf : " << printf_duration.count() << "s" << endl;
    
    return 0;
}

결과:

cout   : 1.024s
printf : 23.381s

4. double 출력 비교 (6자리 소수점, 개행 없음)

일반적인 환경을 시뮬레이션하기 위해 6자리 소수점을 유지하고 setprecision() 함수를 사용했습니다.

코드:

// 테스트 4: double 출력에서의 cout와 printf 비교
#include <iostream>
#include <cstdio>
#include <chrono>
#include <iomanip>
using namespace std;
const int ITERATIONS = 10000000; // 1천만 번 반복
chrono::high_resolution_clock::time_point start_time, cout_time, printf_time;

int main(){
    freopen("output.txt","w",stdout);
    start_time = chrono::high_resolution_clock::now();
    
    for(double counter = 1.0; counter <= ITERATIONS; ++counter){
        cout << fixed << setprecision(6) << 11.45141919 * counter;
    }
    
    cout_time = chrono::high_resolution_clock::now();
    
    for(double counter = 1.0; counter <= ITERATIONS; ++counter){
        printf("%.6lf", 11.45141919 * counter);
    }
    
    printf_time = chrono::high_resolution_clock::now();
    
    freopen("results.txt","w",stdout);
    
    auto cout_duration = chrono::duration_cast<chrono::duration<double>>(cout_time - start_time);
    auto printf_duration = chrono::duration_cast<chrono::duration<double>>(printf_time - cout_time);
    
    cout << "cout   : " << cout_duration.count() << "s" << endl;
    cout << "printf : " << printf_duration.count() << "s" << endl;
    
    return 0;
}

결과:

cout   : 30.008000s
printf : 29.687000s

5. 개행 문자 출력 비교 (cout에서 endl과 \n 모두 테스트)

코드:

// 테스트 5: 개행 문자 출력에서의 cout와 printf 비교
#include <iostream>
#include <cstdio>
#include <chrono>
#include <iomanip>
using namespace std;
const int ITERATIONS = 10000000; // 1천만 번 반복
chrono::high_resolution_clock::time_point start_time, cout_time, endl_time, printf_time;

int main(){
    freopen("output.txt","w",stdout);
    start_time = chrono::high_resolution_clock::now();
    
    for(int counter = 1; counter <= ITERATIONS; ++counter){
        cout << '\n';
    }
    
    cout_time = chrono::high_resolution_clock::now();
    
    for(int counter = 1; counter <= ITERATIONS; ++counter){
        cout << endl;
    }
    
    endl_time = chrono::high_resolution_clock::now();
    
    for(int counter = 1; counter <= ITERATIONS; ++counter){
        printf("\n");
    }
    
    printf_time = chrono::high_resolution_clock::now();
    
    freopen("results.txt","w",stdout);
    
    auto cout_duration = chrono::duration_cast<chrono::duration<double>>(cout_time - start_time);
    auto endl_duration = chrono::duration_cast<chrono::duration<double>>(endl_time - cout_time);
    auto printf_duration = chrono::duration_cast<chrono::duration<double>>(printf_time - endl_time);
    
    cout << "cout   : " << cout_duration.count() << "s" << endl;
    cout << "endl   : " << endl_duration.count() << "s" << endl;
    cout << "printf : " << printf_duration.count() << "s" << endl;
    
    return 0;
}

결과:

cout   : 0.401s
endl   : 11.698s
printf : 18.655s

보너스: 문자열 출력에서의 cout, printf, puts, putchar 비교

코드:

// 보너스: 문자열 출력에서의 cout, printf, puts, putchar 비교
#include <iostream>
#include <cstdio>
#include <chrono>
using namespace std;
const int ITERATIONS = 10000000; // 1천만 번 반복
chrono::high_resolution_clock::time_point start_time, cout_time, printf_time, puts_time, putchar_time;

int main(){
    freopen("output.txt","w",stdout);
    start_time = chrono::high_resolution_clock::now();
    
    for(int counter = 1; counter <= ITERATIONS; ++counter){
        cout << "PERFORMANCE_TEST" << '\n';
    }
    
    cout_time = chrono::high_resolution_clock::now();
    
    for(int counter = 1; counter <= ITERATIONS; ++counter){
        printf("PERFORMANCE_TEST\n");
    }
    
    printf_time = chrono::high_resolution_clock::now();
    
    for(int counter = 1; counter <= ITERATIONS; ++counter){
        puts("PERFORMANCE_TEST");
    }
    
    puts_time = chrono::high_resolution_clock::now();
    
    for(int counter = 1; counter <= ITERATIONS; ++counter){
        putchar('P');putchar('E');putchar('R');
    }
    
    putchar_time = chrono::high_resolution_clock::now();
    
    freopen("results.txt","w",stdout);
    
    auto cout_duration = chrono::duration_cast<chrono::duration<double>>(cout_time - start_time);
    auto printf_duration = chrono::duration_cast<chrono::duration<double>>(printf_time - cout_time);
    auto puts_duration = chrono::duration_cast<chrono::duration<double>>(puts_time - printf_time);
    auto putchar_duration = chrono::duration_cast<chrono::duration<double>>(putchar_time - puts_time);
    
    cout << "cout    : " << cout_duration.count() << "s" << endl;
    cout << "printf  : " << printf_duration.count() << "s" << endl;
    cout << "puts    : " << puts_duration.count() << "s" << endl;
    cout << "putchar : " << putchar_duration.count() << "s" << endl;
    
    return 0;
}

결과:

cout    : 1.034s
printf  : 22.068s
puts    : 0.978s
putchar : 0.968s

결론

double을 출력할 때 printf보다 약간 느린 것(아마도 setprecision() 함수 때문일 가능성이 높음)을 제외하면, 다른 모든 경우에서는 기본적으로 cout이 압도적으로 빠릅니다. 또한 본문에서 cout의 스트림 동기화를 꺼내지 않았는데, 이는 실제 사용에서 매우 일반적인 방법입니다(같은 코드에서 두 가지 다른 시대의 출력 방식을 함께 사용하는 경우는 거의 없으며, scanf/printfcin/cout을 함께 사용하는 것 자체가 신비롭고 오류가 발생하기 쉽습니다).

따라서, 부동소수점수를 출력하지 않는 환경에서는 cout이 더 나은 선택이라고 할 수 있습니다.

또한 개행 문자 출력 실험에서, cout으로 '\n'을 출력하는 것이 endl을 사용하는 것보다 훨씬 빠릅니다. 이는 실제 사용에서 상수 최적화로 활용할 수 있습니다.

물론 보너스 테스트에서 보듯이, 대량으로 문자열(예: "Yes/No" 형태)을 출력할 때는 cout은 재미로 사용할 수 있지만, 가장 빠른 속도를 원한다면 puts를 사용해야 합니다.

업데이트: 사실 속도 차이는 크지 않지만, cout이 여전히 printf보다 약간 빠릅니다.

태그: C++ 성능 비교 cout Printf 출력 함수 최적화

7월 31일 19:39에 게시됨