강의/computer science

[ComputerScience] c++의 I/O Streams (cin, cout)

하기싫지만어떡해해야지 2024. 9. 20. 15:02

이 게시글은

서울대학교 데이터사이언스대학원

조요한 교수님의

데이터사이언스 응용을 위한 컴퓨팅 강의를

학습을 위해 재구성하였습니다.


 

c++의 cin과 cout같은 I/O Streams는

input과 output을 도와주는 프레임워크이다

 

실제로 컴퓨터에서 input과 Output은

밑바닥에서 굉장히 복잡한 과정이 일어나는데

사용자는 이를 알지못해도 입출력 기능을 

사용할 수 있도록 해주는 것이다

 

 

cin

 

 

c++에서 input을 도와주는 오브젝트이다

일반적으로 키보드를 이용해서 입력한다

 

사용자가 키보드로 입력을 해서

입력한 내용을 프로그램 안으로 가지고가는 부분이다

 

위 ppt 그림에서 수도꼭지에서 물이 나오는 부분이

cin이라고 이해하면 좋다

 

수도꼭지를 트는 레버(?)는

cin >> input할거... 

에서 >> 의 역할이다

 

>> 는 extraction operator라고 부르는데

이 extraction operator가 수도꼭지를 틀면서

stream buffer 안에 있는 내용을 프로그램 안으로 가져오게 된다

 

 

사용자가 입력을 하면 stream buffer에 저장했다가

>> 의 오른쪽에 있는 변수에

사용자의 입력값을 저장하게 해준다

 

예를 들어 

cin >> age

이렇게 하면 사용자가 입력한 값은

age라는 변수에 저장된다는 뜻이다

 

c언어에서는 scanf를 통해서 %d, %c등

변수의 타입을 지정해줘야했지만

c++에서는 자동으로 변수 타입을 지정해준다

 

 

그렇다면 user가 input을 넣으면

한 번에 얼만큼 읽어올까?

 

원칙은 extraction operator의 오른쪽에 있는

변수의 타입이 기대하는만큼 읽어온다

 

예를들어서, 오른쪽 변수가 char이면 글자 1개만

기대하기때문에 stream buffer에서 캐릭터 한 개만

읽어오고 멈추게된다

 

혹은 오른쪽 변수가 int이면 

숫자가 있는 한 계속 읽어오다가

non-numeric이 나타나면 멈춘다

 

또 whitespace, tab이 있으면

데이터를 읽어오는 것을 멈추기때문에

string을 계속 읽어오다가

whitespace가 나오면 거기까지만 읽고

멈추게 된다

 

그리고 읽어오는도중 중간에 멈추면

stream buffer에서 다 읽지못한 찌꺼기들이 남아있게되는데

이 찌꺼기들은 다음번 stream buffer가 읽어올때

나머지를 이어서 읽어오게 된다

 

 

cin >> age >> salary >> grade;

와 같이 sequencial하게 cin을 받아올 수도 있다

 

어떻게해서 이렇게 작동이 가능할걸까?

간단한 구현 과정을 이해해보자

 

 

cin은 istream 클래스의 object이다

>>의 method는 실제로는 operator>>()와 같다

다시 말해보자면

cin >> age는 cin.operator >>(age)라고

작성하는 것과 동일하다는 뜻이다

 

그런데 cin 메소드는 반환값으로

cin object인 자신을 반환한다

 

한마디로, cin >> age가 실행되면

반환값으로는 다시 cin이 나온다는 소리이다

 

즉, cin >> age >> salary >> grade;

에서 우선적으로 cin >> age가 실행이 될 것이고

그럼 age가 저장된 이후

cin >> age 메소드는 다시 cin 오브젝트를

반환하게 된다

그러 cin >> salary >> grade;가 되는 것이고

cin >> salary가 실행되면 다시 cin object가 반환되니

cin >> grade;가 실행되게 되는 것이다

 

이러한 과정을 통해

cin은 sequencial하게 input을 할 수 있게 한다

 

 

cin - Error Handling

 

cin에서는 어떻게 에러를 처리할까?

간단하게만 이해해보도록 하자

 

cin에서는 우선 데이터 타입을 늘 체크한다

사전에 정의가 되어있는 fail state 메소드를 사용해

데이터 타입이 같으면 true, 다르면 false를 반환하고

false가 나오면 Error를 띄우게 된다

 

error 메세지를 띄운 후

c.clear()를 통해 error state를 비우고

c.ignore()을 통해 사용자가 input을 넣은 값을

무시를 한다

 

 

cin은 기본적으로 띄어쓰기가 나오면 무조건

입력값을 읽어오는 것을 멈추는데

getline 메소드를 사용하면

띄어쓰기를 포함한 한 줄을 받아올 수 있다

 

 

 

cout

이제 출력 메소드인 cout에 대해 알아보자

 

cout은 cin과 반대인 메소드이다

컴퓨터 내의 어떤 값을 standard output device를 통해

user에게 보여지도록 해주는 것인데

standard output device는 주로

콘솔이나 터미널을 뜻한다

 

보통 cout << "Hello World";

와 같이 쓰는데

여기서 <<는 insertion operator라고 하며

output buffer에 있는 내용을 화면 밖으로

쏟아내보내주는 부분이다

 

cout도 cin과 마찬가지로

standard library의 일부이며

iostream 안에 정의되어있다

 

c언어에서는 printf를 통해

%d, %c와 같이 출력 데이터 타입을

미리 정의해줘야했지만

c++은 마찬가지로 상관없다

 

 

보통 cout을 사용하는 걸 보면

cout << "Hello world" << endl;

이런 방식으로 많이 사용하는 것을

볼 수 있는데

endl은 다음 라인으로 넘어가도록 해주는 역할이다

\n과 동일한 역할을 한다고 보면 된다

 

또한 endl은 output buffer를 flush되게 해주는데

endl을 쓰면 output buffer 안에 남아있는 값들이

모두 user에게 출력되며

buffer 내부는 비게 된다

 

flush를 사용하지 않으면

내가 생각한대로 출력이 되지 않을 수도 있다

 

 

cout - Formatting output

이제 cout에서 출력문을 내가 원하는 형식대로

포맷팅 하는 법을 간단하게 배워보자

 

 

위 ppt 사진을 참고하면

실제로는 저 double pi를 출력하면

소숫점 다섯째짜리까지밖에 뜨지 않는다

 

 

std::septprcision(4)를 사용하면

digit을 반드시 4개를 출력해라는 뜻이다

 

그런데 소수 뒤에 자리만 고정시키고 싶다면

위 ppt처럼

std::fixed를 사용해주면 된다

 

output 결과를 보면

뒤 소숫점 4개까지 출력되는 것을

확인할 수 있다

 

 

std::setw(8)의 뜻은

output값으로 총 8개의 자리가

출력이 되게하라는 뜻이다

 

하지만 그 앞에

std::setfill('0')을 해주면

8자리 이외에 남아있는 공간에는

0으로 채워달라는 뜻이다

 

출력문을 보면 그냥 5의 값인 number가

00000005로 출력되는 것을 볼 수 있다

 

 

std::cerr는 에러메세지를 출력할 때 주로 쓰이는 메소드이다

cout과의 차이점은

cerr는 버퍼를 거치지 않고 출력된다는 점이다

insertion을 수행하는 순간 바로 출력이되고

buffer에 값이 남지 않는다

 

std::clog는 주로 로깅을 위해 사용하는 메소드이다