ios::sync_with_stdio, cin.tie, cout.tie란?
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
Stream
우선 stream에 대한 이해가 먼저 필요하다 우리가 c언어와 c++언어를 가장 처음 배울 때 적는 것은 사실 아래에
두 헤더파일이다 각각은
- stdio: standard input output
- iostream: input output stream
#include <stdio.h>
#include <iostream>
표준 스트림(standard streams)은 특정한 프로그래밍 언어 인터페이스뿐 아니라 유닉스 및 유닉스 계열 운영 체제(어느 정도까지는 윈도에도 해당함)에서 컴퓨터 프로그램과 그 환경(일반적으로 단말기) 사이에 미리 연결된 입출력 통로를 가리킨다. 우리는 키보드를 통해 컴퓨터에 타이핑을 하여 글과 코드를 넣어 프로그램을 만들고, 프로그램이 실행되면 cli 혹은 gui를 통하여 결과를 볼 수 있다. 프로그램과 입출력을 하는 단말기 사이에 연결된 통로가 stream이다.
과거 입출력을 다루는 것은 스크린, 키보드와 같은 H/W 장치와 OS 간에 얽혀 복잡한 일이었지만, 현재는 stream을 추상화하여 하나의 파일처럼 다룰 수 있게 함으로써 쉽게 사용할 수 있다. 그래서 freopen, fopen과 같은 함수로 파일도 스트림으로 연결하여 scanf, cin과 같은 함수로 가져올 수 있는 것이다.
Standard Stream
유닉스에서는 프로그램을 사용할 때, 사용자가 따로 지정하지 않아도 3개 정도의 stream을 자동으로 연결해줍니다. 입력, 출력, 에러 스트림. 이러한 stream들을 표준 스트림(Standard Stream)이라고 한다.
- c에서 표준스트림은 다음과 같다.
- stdin
- stdout
- stderr
- c++에서 표준스트림은 다음과 같다.
- std::cin
- std::cout
- std::cerr
- std::clog
- std::wcin
- std::wcout
- std::wcerr
- std::wclog
Sync_with_stdio
일반적으로 c의 stream과 c++의 stream은 동기화 되어 있기 때문에, 한 코드를 작성할 때 c style 코드와 c++ style 코드를 혼용하여도 같은 stream 버퍼에 쌓이기 때문에 의도한 대로 입출력을 할 수 있다. 또한 multi-threading을 사용할 때, 각각 출력 연산을 수행 하여도 충돌이 일어나지 않다. 일반적으로 std::cout, std::cin을 사용할 때 프로그램의 속도가 scanf, printf보다 느린 이유다. 만약 동기화를 해제한다면 각 스트림이 각각의 버퍼를 가지고 독립적으로 사용할 수 있다. 연산이 줄기 때문에 입출력 속도를 증가시킬 수 있다. 하지만 멀티 쓰레딩 시 충돌이 발생할 수 있고, 각각 연산하여 저마다의 버퍼를 사용하여 출력하기 때문에 입출력 순서가 보장되지 않다. 이러한 입출력 스트림의 동기화를 설정하는 코드가 ios::sync_with_stdio(1)인 것이다. 매개변수를 false로 바꾸게 되면 동기화를 해제하게 된다.
동기화를 해제하고 c와 c++의 stream을 혼용하여 작성한 코드의 결과.
#include <cstdio>
#include <iostream>
int main() {
std::ios::sync_with_stdio(false);
std::cout << "1\n";
std::printf("2\n");
std::cout << "3\n";
}
꼭 순서가 다르다는 보장도, 같다는 보장도 되지 않습니다. 연산과 flush에 따라 어떻게 달라질지 알 수 없다.
#include <cstdio>
#include <iostream>
int main() {
std::ios::sync_with_stdio(false);
std::cout << "1" << std::endl;
std::printf("2\n");
std::cout << "3" << std::endl;
}
std::cin, std::cout을 사용하여 빠른 입출력을 원하는 경우 스트림간 동기화를 해제해주면 되지만, c style과 c++ style의 stream을 혼용하게 되면 문제가 발생하기 때문에, 한 가지만 사용해야 한다.
cin.tie(0), cout.tie(0)
cin과 cout은 default로 tie되어 있다. tie한다는 것은 두 개의 stream이 sync되어 있기 때문에 한 스트림에서 다른 스트림이 작업 요청을 하게 되면, 작업했던 내용을 flush(buffer에 쌓아둔 데이터를 모두 내보내는 또는 가져오는)한다는 의미다. 일반적으로 버퍼가 가득 차게 되면 flush를 하게 된다다. 적절히 flush를 하지 않고 긴 문자열을 입출력하는 경우 개행이나 뒷쪽의 문자열이 잘리는 경우가 발생할 수 있다. 이럴 때 의도적으로 buffer flush 코드를 종종 넣곤 한다. 하지만 매우 빠른 시간 안에 입출력이 이루어지기 때문에 어지간히 느린 경우가 아니고서야 굳이 수시로 flush를 할 필요가 없다. 코딩테스트의 경우 그야말로 어떻게 되든 결과가 보이기만 하면 되기 때문에 더욱 의미가 없다. 따라서 입출력의 변환이 빈번하게 이루어지는 경우 untie를 하게 되면 더욱 입출력이 빨라지게 된다. 다만 동기화와 똑같이 untie를 하게 되면, 출력이 flush되지 않고 입력을 받는 경우가 발생할 가능성이 있다.
std::cout << "Enter name:";
std::cin >> name;
위와 같이 "Enter name"이 출력되지 않고 입력을 먼저 요구하는 상황이 발생할 수 있다는 의미.
std::endl
개행에 \n 대신 endl을 쓰게 되면 출력 속도가 훨씬 느려진다. 그 이유는 endl은 줄바꿈과 동시에 flush를 하기 때문. 상식적으로는 flush를 적절히 하는 것이 원하는 입출력 순서를 보장받을 수 있지만, 코딩테스트에서는 굳이 그럴 필요가 없기 때문에 escape sequence를 사용하는 편이 좋다.
'코딩테스트 > 공통' 카테고리의 다른 글
최솟값과 최댓값 표현하기 (0) | 2022.08.12 |
---|---|
C++ stringstream 사용법 (문자열에서 공백 제외 추출, 특정값) (0) | 2022.08.11 |
C++ max_element(), min_element() 최대값, 최소값 (0) | 2022.08.11 |
백준 골5 달성 (0) | 2022.06.30 |
C++ 문자열 공백 제거하는 방법 (0) | 2022.06.27 |