일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- uuid-ossp
- 스타트업
- 엣지컴퓨팅
- mistel키보드
- 이노베이션아카데미
- schema first
- 쿠버네티스
- adminbro
- 텍스트북
- 동료학습
- 레이캐스팅
- 자료구조
- Cloud Spanner
- 정렬
- GraphQL
- 도커
- 부동소수점
- SFINAE
- 42seoul
- psql extension
- 파이썬
- 42서울
- 프라이빗클라우드
- 스플릿키보드
- c++
- raycasting
- 어셈블리어
- 창업
- enable_if
- 어셈블리
- Today
- Total
written by yechoi
[C++] std::endl이 \n과 다른 점 - 출력버퍼 이해하기 본문
C++ 시작하는 친구가 문득 std::endl이랑 '\n'이랑 뭐가 다르냐고 물었다. 이전에 훑어보기론 std::endl
은 출력버퍼를 비우고 \n
은 그렇지 않다고 봐, 이렇게 설명을 해줬다. 그랬더니 버퍼가 뭐냐, 버퍼를 비운다는 게 뭐냐, 출력버퍼를 왜 비우냐 묻는다. 정확히 이유를 알진 않고 관습적으로 사용하던 중이었는데, 막상 질문을 받으니까 너무나 궁금해지는 것,,, 이 참에 찾아보는 std::endl
과 \n
의 다른 점! 버퍼란 무엇이냐는 물음부터 시작한다.
버퍼란
버퍼는 임시 메모리 공간이다. 입력이나 출력을 바로바로 전달하는 게 아니라, 버퍼에 담아둘 수 있다. 버퍼를 사용하면서 얻을 수 있는 장점은
- 문자를 한번에 전달하므로 전송시간이 적게 걸림
- 문자를 잘못 입력했으면 수정 가능
- 시스템콜을 적게 호출해 자원을 아낌
이렇게 임시적으로 버퍼에 저장해두는 걸 버퍼링이라고 칭한다. 버퍼링의 방식엔 두 가지가 있는데
- 버퍼가 다 찰 때까지
- 개행을 의미하는 문자가 나타날 때까지
버퍼를 비운다는 건
버퍼에 저장돼있던 내용을 내보낸다는 거다. stdout 버퍼를 비우면, 화면으로 그 내용이 출력된다. 이를 flush 한다고한다.
버퍼를 비우는 케이스는 버퍼링을 하는 경우를 뒤집으면 된다.
- 버퍼가 다 찼을 때
- 개행을 의미하는 문자가 나타났을 때
앞선 2번의 예를 들자면
int main(void)
{
std::cout << "hello" << std::endl;
sleep(5);
return (0);
}
이 코드는 hello가 출력된 뒤 5초가 흐르고 종료된다.
int main(void)
{
std::cout << "hello";
sleep(5);
return (0);
}
이 코드는 5초가 흐르고 hello가 출력된다.
앞선 코드는 버퍼를 비우라는 사인인 std::endl
이 나왔기 때문에, hello를 먼저 출력하고 종료한다. 뒤의 코드는 버퍼를 비우라는 사인이 없었기 때문에 buffer에 hello가 쌓인 채로 5초가 지나고, 프로그램이 종료되면서 커널에 의해 버퍼를 비운다.
한가지가 더 있는데 인위적으으로 비워주는 경우다.
- C 표준 라이브러리
fflush()
를 사용할 때
int main(void)
{
std::cout << "hello";
fflush(stdout);
sleep(5);
return (0);
}
std::endl
이 있던 것처럼 먼저 hello를 출력하고 5초가 지난다.
🔗flush에 대한 고찰
🔗 C에서 입력버퍼(stdin)과 출력버퍼(stdout)
std:: endl과 \n의 차이
std::endl
과 \n
의 차이는 여기서 나타난다. std::endl
은 위의 2번에 해당하는 문자다. std::endl
이 입력되면 버퍼는 자동으로 비워진다.
\n
의 경우 버퍼를 비우지 않는다. 다만 구현체에 따라서 std::endl
처럼 버퍼를 비우도록 처리하도록 하는 경우도 있다. 그렇지만 장담할 수 없으므로, 버퍼를 비우고 싶으면 std::endl
을 사용해야 한다.
속도도 차이난다. 버퍼를 비우는 std::endl
이 느리고, 비우지 않는 \n
이 빠르다. 굳이 즉시 출력해 줘야하는 게 아니라면, \n
으로 모아뒀다가 출력하는 게 시간을 줄일 수 있다. 백준에서 타임아웃 문제로 이 둘의 차이를 궁금해 하는 사람들이 많다.
~이 둘이 비우는 버퍼가 std::endl
은 buffered IO, \n
은 streamed IO로 다르다고 하는데, 구체적인 자료는 찾지 못했다. ~
버퍼를 비워주지 않아서 문제가 생기기는 해?
개인적으로는 입력버퍼를 비우지 않아서 생기는 문제는 봤어도, 출력버퍼를 비우지 않아서 생기는 문제는 경험한 적이 없다. 그래서 처음에는 '굳이 비우는 걸 신경써야 하는 거야'라는 의문이 생겼던 것도 사실.
여러가지 경우가 있겠지만 이런 경우에 문제가 생길 수 있다.
-
앞선
sleep()
사용 예제처럼 출력에 시간차가 나는 경우 -
fork()
로 프로세스가 나뉜 상황
여기서는 write와 printf를 혼용했을 때 문제가 생겼다고. write는 버퍼 내용을 그대로 출력하는 반면, printf는 종료문자('\0', '\n')를 만나기 전까지 출력하지 않기 때문.
갑자기 궁금증 폭발해서 찾아본 내용. 묵혀놨던 궁금증인 'C++에선 string1 == "abc"
이런 연산이 왜 먹힐까'가 다시 떠오르긴 했는데, 다시 묵혀두기로 하고...ㅋㅋㅋㅋ 코테 준비하러 총총...