본문 바로가기

진리는어디에/C++

[C++] iomanipulator 완벽 가이드

들어가며

이번 포스트에서는 C++의 출력 포멧을 조절할 수 있는 iomanipulator에 대해 살펴 볼 것이다. 자세한 동작 원리는 나중에 연산자 오버로딩에서 깊게 살펴 보도록하고 이번 시간에는 iomanipulator의 개념과 사용 방법을 위주로 다룰 예정이다.

std::dec 변수 값을 10진수로 출력
std::hex 변수 값을 16진수로 출력
std::setw 문자열 출력시 개수 지정
std::setfill 공백을 채울 문자 지정
std::left 문자열 왼쪽 정렬

iomanipulator란?

C++에서 입력이나 출력의 형태를 지정하기 위해 사용하는 것을 iomanipulator라고 한다.

설명에 앞서 먼저 아래의 예제 코드를 살펴 보도록하자. 아래 코드는 간단하게 int 타입의 변수를 출력하고 있다. 기본적으로 정수를 출력하게 되면 10진수 포멧으로 출력 된다.

#include <iostream>
#include <iomanip>

int main()
{
    int n = 10;
    std::cout << n << std::endl;
    return 0;
}

// OUTPUT
// 10

만일 위의 10진수 출력을 16진수로 변경하고 싶다면 변수 출력 앞에 std::hex를 추가하면 int 타입의 변수 n을 출력할 때 16진수로 출력 해달라는 의미가 된다.

std::cout << n << std::endl;
std::cout << std::hex << n << std::endl;

// OUTPUT
// 10
// a

위와 같이 std::hex를 추가하면 10진수 10이 16진수 a로 변경되어 출력 되는것을 확인할 수 있다.

만일 std::hex 라인 아래에 다시 n을 출력하는 코드를 추가하게 된다면 출력 결과는 어떻게 될까? 결과는 한번 16진수로 변경 후에는 계속 16진수로 출력되는 것을 볼 수 있다.

std::cout << n << std::endl;
std::cout << std::hex << n << std::endl;
std::cout << n << std::endl;

// OUTPUT
// 10
// a
// a

std::hex는 출력되는 라인 하나에만 영향을 미치는 것이 아니고 그 뒤에 출력되는 모든 int 타입 변수들에 영향을 미치는 것을 알 수 있다. std::hex의 의미는 이 이후 부터는 std::cout으로 출력할 때 int 타입의 값을 16진수로 출력하겠다는 의미다.

std::cout << std::hex; // 이 이후 부터는 16진수로 출력
std::cout << n << std::endl;

// OUTPUT
// a

16진수로 변경한 출력을 다시 10진수로 돌리기 위해서는 std::dec를 사용한다.

std::cout << n << std::endl;
std::cout << std::hex << n << std::endl; // 16 진수 출력
std::cout << std::dec << n << std::endl; // 10 진수 출력

// OUTPUT
// 10
// a
// 10

위와 같이 iomanipulator를 이용해 출력되는 형태를 지정할 수 있다.

우리 나라 말로 표현하자면 '조정자 함수' 또는 '조작자 함수' 라고도 표현한다. 여기서 '함수'라고 불리는 것에 주목해 볼 필요가 있다. 그렇게 보이진 않지만 사실 std::hex 나 std::dec의 정체는 함수이기 때문이다. 어떻게 저 manipulator들이 함수인지를 설명하기 위해서는 굉장히 깊게 설명을 해야하므로 지금 단계에서는 변수 값을 출력하기 전에 형태를 지정해주는 무엇인가 정도로 이해하고 넘어가도록 하자. 보다 자세한 사항은 추후 연산자 재정의 포스트에서 자세히 다뤄 보도록 하겠다.

iomanip 헤더 포함

앞에서 간단한 iomanipulator가 무슨 일을 하는지, 어떻게 사용하는지에 대해 간단히 살펴 보았으므로 지금 부터는 코드 레벨에서 차근차근 다시 살펴 보도록하겠다.

가장 먼저 C++의 iomanipulator를 사용하기 위해서는 iomanip 헤더를 포함해야 한다. iomanip는 iomanipulator의 약자다.

#include <iomanip>

iomanipulator 활용

헤더를 인클루드 했다면 이제 본격적으로 사용 방법에 대해 자세히 살펴 보도록하자.

std::setw

std::setw 함수는 출력 되는 변수의 글자수를 맞춰 준다. 예를 들어 아래와 같이 'hello'를 출력한다고 가정하자.

#include <iomanip>

int main()
{
    std::cout << "hello" << std::endl;
    return 0;
}

// OUTPUT
// hello

출력 결과는 앞(왼쪽)에서 부터 텍스트가 출력 된다. 만일 우리가 std::setw를 이용해 출력되는 글자수를 지정해 준다면 글자수에 맞춰 오른쪽 정렬을 해준다. 설명으로는 이해가 힘들테니 코드와 결과를 확인 해보자.

std::cout << std::setw(10) << "hello" << std::endl;

// OUTPUT
//      hello

std::setw(10)으로 값을 줬을 때 총 글자 길이 10만큼에서 hello 텍스트를 오른쪽 정렬하고 앞 부분을 공백 처리해준다.

std::setfill

앞에서 std::setw를 이용해 공백을 만들었다면 그 공백을 채워줄 문자를 지정할 수 있는 함수다. 만일 std::setfill('#')과 같이 지정하면, 앞으로 출력될 공백을 #으로 채워 달라는 의미가 된다.

std::cout << std::setw(10) << std::setfill('#') << "hello" << std::endl;

// OUTPUT
// #####hello

std::left

std::setw 를 이용해 오른쪽 정렬을 했다면 std::left를 왼쪽 정렬로 변경할 수 있다. 아래 코드를 실행하면 hello가 왼쪽 정렬로 먼저 출력 되고 #이 뒤에 채워지는 것을 확인할 수 있다.

std::cout << std::setw(10) << std::setfill('#') << std::left << "hello" << std::endl;

// OUTPUT
// hello#####

std::hex, std::dec

맨 앞에서 설명 했으므로 생략하도록 한다.

마치며

이상 C++ iomanipulator의 개념과 자주 사용되는 manipulator 함수들을 살펴 보았다. 본 포스트에서 소개된 것 외에도 다른 manipulator 함수들이 있는데 이는 [여기]에서 확인할 수 있다.

 

Input/output manipulators - cppreference.com

Manipulators are helper functions that make it possible to control input/output streams using operator<< or operator>>. The manipulators that are invoked without arguments (e.g. std::cout << std::boolalpha; or std::cin >> std::hex;) are implemented as func

en.cppreference.com

위 페이지의 세부 항목으로 들어가 보면 각 manipulator의 소개와 예제 코드까지 정리되어 있으므로 필요할 때 마다 찾아 보면 된다. 문제는 설명이 잘 되어 있긴한데 너무 잘되어 있어서 아직 이해하기 어려운 수준의 설명도하고 있으므로 지금 단계에서는 적당히 예제 위주로 사용법을 익히는데 집중하도록 하자.

부록 1. 같이 읽으면 좋은 글

유익한 글이었다면 공감(❤) 버튼 꾹!! 추가 문의 사항은 댓글로!!