열거형 enumerated types 본문
열거형 enumerated types
컴퓨터는 모든 숫자들을 정확하게 구분 할 수 있는데 사람은 간단한 숫자도 알아차리기 어려운 경우가 많다.
그래서 프로그래머들은 비슷한 유형의 다양한 옵션들을 기호적으로 표현하기 위해서 열거형을 사용한다.
C++에는 많은 자료형이 내장되어 있다.
하지만 이 자료형들이 원하는 걸 표현하기에 항상 충분하지는 않다.
그래서 C++은 프로그래머들이 자신만의 자료형을 만들 수 있게 해 주는 기능을 포함하고 있다.
이러한 자료형을 사용자 정의 자료형이라고 한다.
열거형은 가능한 모든 값이 기호 상수(열거형)로 정의되는 자료형이다. 열거형은 enum 키워드를 통해 정의된다.
게임을 만든다고 가정하고 캐릭터가 맞았을때 피해치를 얼머나 줘야하는 지 계산하는 함수를 만들어보자.
이때 어떤 무기로 맞았느냐에 따라서 damage 값이 달라질 수 있다.
여기서 문제는 프로그래머 입장에서는 칼이 0번이었고 해머가 1번이었고 활이 2번 이런것들을 외우기 어렵다.
이렇게 되면 자연스럽게 실수가 잦아진다.
이런 실수를 방지하고 좀 더 편하게 기호적으로 옵션들을 표현하기 위해서 열거형을 사용한다.
열거형 정의하는 방법
ex) COLOR
이렇게 나열하는 것을 열거한다고 한다.
마지막 COLOR_GREEN 옆에 콤마가 없어야 될 것이라고 생각할 수 있는데 있어도 된다.
프로그래머의 편의를 위해서 허용해준다.
열거형을 정의해도 메모리는 할당되지 않는다.
열거된 유형의 변수가 정의된 경우, 해당 변수에 대해 메모리가 할당된다.
각 열거자는 쉼표(,)로 구분되고, 전체 열거는 세미콜론(;)으로 끝난다.
Naming enums
enum 식별자는 대문자로 시작하는 경우가 많으며,
열거자(enumerator)는 종종 모두 대문자로 이름이 지어진다.
열거자는 열거와 같은 네임스페이스에 배치되므로,
열거자 이름은 같은 네임스페이스 내의 여러 열거(enum)에서 사용할 수 없다.
enum도 여러개를 정의 할 수 있는데
이럴경우 앞에 COLOR_ 또는 FEELING_을 붙여주지 않고 그냥 BLUE를 정의했다고 하면
위에있는 Color의 BLUE와 밑에있는 Feeling 의 BLUE가 같아서 컴파일이 되지않는다.
따라서 이름 충돌을 방지하기 위해서 열거자 앞에 접두어를 붙이는 것이 일반적이다.
서로 달라보이는 그룹의 열거형의 값도 전역처럼 작동을 한다.
다른 중괄호로 묶여있으니까 서로 영향을 안주겠지 싶었는데 영향을 준다. 주의해야 한다
이 문제를 해결하는 방법은 enum class가 있다.
Enumerator values
각 열거자는 열거 목록의 위치에 따라 정수 값이 자동으로 할당된다.
기본적으로 첫 번째 열거자에는 정수 값 0이 할당되며, 각 이후 열거자에는 이전 열거자보다 1 더 큰 값이 할당된다.
그리고 열거자의 값을 명시적으로 정의 할 수 있다.
이러한 정수 값은 양 또는 음의 값일 수 있으며 다른 열거자와 같은 값을 공유 할 수 있다.
정의되지 않은 모든 열거자는 이전 열거자보다 1이 더 큰 값이 부여된다.
이때 COLOR_BLUE와 COLOR_GREEN이 수동으로 5가 대입이 되어있는데
이렇게 되면 구분을 할 수가 없어서 문제가 생긴다.
가장 좋은것은 수동으로 할당하는것 보다는 자동으로 기본 할당되게 쓰는게 가장좋다.
Enum type evaluation and input/output
열거형 값은 정수로 평가되므로 정수 변수에 할당할 수 있다.
std:cout은 정수 출력 방법을 알고 있으므로 정수로 출력할 수도 있다.
그럼 이걸 정수형처럼 쓸 수 있구나 생각 할 수 있는데 의외로 그렇게 쓰는 것은 막아놓았다.
이렇게는 쓸 수 없다.
이런식을오 바로 int 형을 넣는 것은 안되고
casting을 이용하여 할 수는 있다.
static_cast를 통해 강제로 변환할 수 있다.
COLOR_GREEN이라고 안하고 3을 넣어서 casting을 할 때에는 뭔가 특별한 이유가 있겠지라고 추측을 해볼 수는 있다.
또한 컴파일러는 std::cin을 사용하여 열거형을 입력 할 수 없다.
우회하는 방법은 있다.
정수를 읽고, static_cast를 사용하여 컴파일러가 정수 값을 열거형으로 입력하도록 하는 방법이있다.
열거형은 고유한 자료형으로 간주한다. 따라서 열거형에 다른 열거형을 할당하려고 하면 컴파일 오류가 발생한다.
Animal animal = COLOR_BLUE; //will cause compiler error
상수(const) 변수와 마찬가지로 열거형은 디버거에 표시되므로 #define보다 유용하다.
또한, 열거형은 정수 자료형의 일부로 간주하므로 열거형 변수에 할당할 메모리 크기는 컴파일러에 따라 결정된다.
C++ 표준에 따르면 열거형 크기는 모든 열거형 값을 나타낼 만큼 커야 한다.
대부분 열거형 변수는 표준 int와 같은 크기다.
enum을 한번 정의해두면 여러 곳에서 사용하고 싶을 수 있다.
프로그램 전체에서 다양한 컬러에 대한 일종의 플래그들을 반복해서 사용하고 싶은 경우가 있는데
전방선언을 하기보다는 보통 헤더 파일을 하나 만들어서 거기에 집어넣고 include 해서 사용하는 방식을 선호한다.
enum타입을 헤더파일에 넣고 include 해서 사용하는거 연습해보면 좋다.
열거형은 언제 유용할까?
열거형은 특정한 상태 집합을 나타내야 할 때 코드 문서화 및 가독성 목적으로 매우 유용하다.
예를들어, 함수는 함수 내부에 문제가 발생했을 때 오류 코드를 나타내기 위해 호출자에게 정수를 반환하는 경우가 많다.
일반적으로 오류 코드를 나타내는 데는 음수가 사용된다.
int readFileContents()
{
if(!openFile())
return -1;
if(!readFile())
return -2;
if(!parseFile())
return -3;
return 0; //success
}
하지만 매직 넘버를 사용하는 것은 좋지 않다.
대신에 열거형을 사용하는 것이 좋다.
enum ParseResult
{
SUCCESS = 0,
ERROR_OPENING_FILE = -1,
ERROR_READING_FILE = -2,
ERROR_PARSING_FILE = _3
};
ParseResult readFileContents()
{
if(!openFile())
return ERROR_OPENING_FILE;
if(!readFile())
return ERROR_READING_FILE;
if(!parseFile())
return ERROR_PARSING_FILE;
return SUCCESS;
}
위 코드는 매직 넘버를 반환하는 것 보다는 훨씬 가독성이 좋다.
또한 호출자는 해당 열거자에 대해 함수의 반환 값을 테스트 할 수 있으며,
이는 특정 정수 값에 대한 반환 결과를 테스트하는 것 보다 이해하기 쉽다.
if(readFileContents() == SUCCESS)
{
//do something
}
else
{
//print error message
}
열거형은 관련 집합을 정의할 때도 사용하기 좋다.
예를 들어, 플레이어가 아이템 하나만 가지고 다닐 수 있는 게임을 만든다고 가정해보자.
아이템은 여러가지 종류가 있다.
#include <iostream>
#include <string>
using namespace std;
enum ItemType
{
ITEMTYPE_SWORD,
ITEMTYPE_TORCH,
ITEMTYPE_POTION
};
string getItemName(Item Type item Type)
{
if(itemType == ITEMTYPE_SWORD)
return string("Sword");
if(itemType == ITEMTYPE_TORCH)
return string("Torch");
if(itemType == ITEMTYPE_POTION)
return string("Potion");
return string("???");
}
int main()
{
//ItemType is the enumerated type we've defined above.
//ItemType is the name of the variable we're defining (of type Item Type).
//ITEMTYPE_TORCH is the enumerated value we're initializing variable itemType with.
ItemType itemType = ITEMTYPE_TORCH;
cout << "You are carrying a " << getItemName(itemType) << endl;
return 0;
}
많은 프로그래밍 언어에서 불리언(boolean)을 정의하기 위해 열거형을 사용한다.
bool은 기본적으로 false 와 true 의 두 열거자를 가진 열거형이다.
그러나 C++에서 true 와 false는 열거자 대신 키워드로 정의되어있다.
주의하기
enum은 int로 내부적으로 저장되는것같지만
실제로 문법상으로는 int와 100% 호환되지 않는다는거 주의
필요한 경우에는 casting 으로 변환을 할 수는 있다
'💘 C++ > 변수범위, 변수형' 카테고리의 다른 글
자료형에게 가명 붙여주기 Type aliases, 고정너비 정수 fixed-width integers (0) | 2022.01.23 |
---|---|
영역 제한 열거형 enum class (0) | 2022.01.23 |
문자열 std::string (0) | 2022.01.23 |
형변환 Type Conversion (0) | 2022.01.17 |
auto 키워드와 자료형 추론 (0) | 2022.01.16 |