C++ 공부를 시작했다. 김포프님의 POCU 아카데미로 C++ 수업을 수강하고 있으며, 해당 진도에 맞춰서 학습한 내용을 블로그 포스팅으로 정리해 볼까 한다. C++을 공부하는 목적은 프로그래머로서 언매니지드 언어를 하나 정도는 잘 쓸 줄 알아야 한다는 책임감(?)과 이 공부를 통해 컴퓨터 구조나 프로그래밍 언어를 컴퓨터가 어떻게 이해하는지, OOP 개념 등에 대해서도 전반적으로 공부를 해 보기 위함이다.
오늘은 그 첫 번째 순서로 입출력에 대한 내용을 다뤄본다. 처음이라 그리 어려운 내용은 아니다.
출력(Output)
C++로 Hello World를 출력하는 코드는 다음과 같다.
cout << 을 통해서 출력을 하고, 이후 설명하겠지만 cin >> 을 통해서 입력을 한다. 여기서 cout은 출력 스트림, cin은 입력 스트림이다.
출력 부분에서 알아야 할 개념이 바로 namespace와 using이다.
만약에 다른 목적으로 사용되지만 그 이름이 같은 두 개의 함수를 쓰기 위해서는 어떤 식으로 코드를 작성해야 할까? 함수나 클래스의 이름이 그냥 중복되어 나타나면 컴파일 에러가 나게 된다. 자바에서는 이를 패키지를 통해서 처리를 하며, C++의 네임스페이스는 자바의 패키지와 비슷한 개념이라고 이해를 하면 된다.
네임스페이스를 사용하면 이와 같이 중복되는 이름의 함수나 클래스도 사용할 수가 있다.
자바에서 import 를 통해 미리 만들어진 패키지를 사용하는 것처럼, C++에서는 using을 통해 다른 라이브러리의 중복되는 코드를 줄여준다. 예를 들어 cout의 경우도 원래는 std::cout 이렇게 항상 써 줘야 하는데 using namespace std를 통해 그냥 cout으로 출력문을 작성할 수가 있다.
그리고 C++에서는 출력 형식을 어느정도 맞춰서 해주는 출력형식 지정(Output Formatting) 연산자들이 있다. 이 연산자들은 조정자(Manipulator)의 역할을 한다. 예를 들면 우리가 일반적으로 사용하는 10진수를 16진수로 출력하는 방법은 다음과 같다.
이와 같은 조정자를 사용하면 직관적이고 깔끔한 코드를 쓸 수가 있다. 이렇게 사용되는 조정자는 정말 많은데 대표적인 것들은 다음과 같다.
- showpos/noshowpos : 양수인 경우 +를 보여줄지 / 그런거 안 보여줄지
- dec/hex/oct : 10진법 / 16진법 / 8진법
- uppercase/nouppercase : 대문자로 바꿔라 / 대문자로 바꾸지 마라
- showbase/noshowbase : 몇진법인지 표기해줘라 / 표기해주지 마라
- 등등...
조정자에 대한 더 많은 정보는 C++ 공식 문서를 참고하기 바란다. 그리고 조정자는 cout 메서드를 사용해서 나타내는 것도 가능하다. 대표적인 메서드로 setf()와 unsetf()가 있다.
// 조정자 1
cout << showpos << number;
// cout 멤버 메서드 1
cout.setf(ios_base::showpos);
cout << number;
// 조정자 2
cout << setw(5) << number;
// cout 멤버 메서드 2
cout.width(5);
cout << number;
입력(Input)
입력값은 앞서 말한 것처럼 입력 스트림을 통해서 값을 받는다.
char firstName[20];
cin >> firstName;
참고로 scanf 방식으로 값을 받는 것은 위험하다. 왜냐하면 문자 배열(ex. char firstName[4])이 어느정도 메모리를 할당 받는지 실행 중에는 알 수가 없기 때문이다. scanf()는 경계 검사를 하지 않는다. 그래서 일반적으로 스트링 뒤에 특수한 문자를 넣어서 여기서 스트링이 끝남을 표시한다. cin으로 값을 받는 것도 똑같은 문제가 있다. cin은 char 배열의 길이를 알 수가 없다.
그러면 C++에서는 입력값의 길이 검사를 어떻게 할까? 우리는 setw()라는 조정자를 사용하여 길이를 제한할 수 있다. 버퍼 사이즈에 따라서 알아서 맞춰서 읽어오고 null character를 붙여 준다.
이번에는 스트림 상태(Stream States)에 대해서 설명해 보려고 한다. 스트림으로 값을 받다가 실패를 할 경우 어떻게 처리를 할 건지에 대해서 좀 더 직관적으로 수행할 수 있다.
스트림 상태를 구성하는 대표적인 요소들은 다음과 같다.
- 네임스페이스 : ios_base
- 비트 플래그 : goodbit / eofbit / failbit / badbit
- 메소드 버전 : good() / eof() / fail() / bad()
예를 들어 다음과 같은 코드가 있다고 했을 때 eofbit와 failbit는 아래 표와 같다.
int number;
cin >> number;
456abc를 입력값으로 받으면 456까지 읽고 멈추는데, eof가 없기 때문에 eofbit도 unset이고, 숫자를 읽었기 때문에 failbit도 unset이다. 456의 경우는 마지막 엔터를 누르고 저장하면 eof가 아닌데, 엔터를 누르지 않고 저장한 파일에서 데이터를 불러오는 경우 eof로 인식하여 eofbit가 set이 될 수도 있다. 따라서 두 가지 경우를 모두 테스트 해 보아야 한다.
다음으로는 입력값을 버리는 메서드에 대해서 알아본다.
- clear() : 스트림을 좋은 상태로 돌려줌
- ignore() : 아래 예제들은 파일 끝에 도달하거나 지정된 수만큼 문자를 버리면 멈춤
- get() : 뉴라인 문자를 만나기 직전까지 모든 문자를 가져옴. 뉴라인 문자는 입력 스트림에 남아 있음
- getline() : 뉴라인 문자를 만나기 직전까지 모든 문자를 가져옴. 뉴라인 문자는 입력 스트림에서 버림
cin.clear();
cin.ignore(); // 문자 1개를 버림
cin.ignore(10); // 문자 10개를 버림
cin.ignore(10, '\n'); // 문자 10개를 버림. 단, 그 전에 뉴라인 문자를 버리면 곧바로 멈춤
cin.ignore(LLONG_MAX, '\n'); // 최대 문자 수를 버림. 단, 그 전에 뉴라인 문자를 버리면 곧바로 멈춤
// 99개 문자를 가져오거나 뉴라인 문자가 나올 때까지의 문자를 가져오고, 가져온 문자들을 char 배열에 배치함
get(firstName, 100);
// 99개 문자를 가져오거나 '#'문자가 나올 때까지의 문자를 가져오고, 가져온 문자들을 char 배열에 배치함
get(firstName, 100, '#');
참고자료
- C++ 언매니지드 프로그래밍, 포큐 아카데미
'Prog. Langs & Tools > C++' 카테고리의 다른 글
[C++] Ch06. OOP 3 (0) | 2020.10.19 |
---|---|
[C++] Ch05. OOP 2 (0) | 2020.10.01 |
[C++] Ch04. OOP 1 (0) | 2020.09.22 |
[C++] Ch03. 파일 입출력(I/O) (0) | 2020.08.26 |
[C++] Ch02. 참조, 문자열 (0) | 2020.08.11 |