23. 열거형 사용하기
하나의 이름으로 서로 관련있는 항목들을 묶어서 관리해주는 열거형 형식(열거형)에 대해서 학습하도록 하겠습니다.
> // 열거형(Enumeration): 하나의 이름으로 서로 관련있는 정수 값을 갖는 상수 집합을 정의
23.1. 열거형 형식 사용하기
C 언어에서 열거형(Enumeration) 형식은 기억하기 어려운 상수들을 기억하기 쉬운 하나의 이름으로 묶어 관리하는 표현 방식입니다. 일반적으로 열거형으로 줄여 말합니다. 열거형을 사용하면 여러 개의 값 리스트를 하나의 이름으로 코드 상에서 묶어서 관리할 수 있는 장점이 있습니다. 열거형은 enum
키워드를 사용하고 이늄으로 읽습니다.
23.2 열거형 만들기
이미 만들어 있는 열거형이 아닌 우리가 원하는 열거형을 직접 정의해서 사용할 수 있습니다. 이를 사용자 정의 열거형으로 부릅니다. 사용자 정의 열거형은 다음과 같이 enum
키워드를 사용하여 선언할 수 있습니다.
enum 열거형명
{
열거형변수1,
열거형변수2,
열거형변수3
};
열거형 선언시 기본값을 설정할 수 있습니다.
enum 열거형명
{
열거형변수1 = 기본값1,
열거형변수2 = 기본값2,
열거형변수3 = 기본값3
};
23.3 열거형을 사용한 방향(상하좌우) 관련 문자열 상수화
C 언어에서 열거형을 만드는 가장 기본적인 모양을 코드로 설명합니다.
코드: enum_direction.c
// 열거형을 사용한 문자열 상수화
#include <stdio.h>
// 열거형 선언: 상하좌우
enum Direction
{
Top, // 0
Bottom, // 1
Left = 10, // 10
Right // 11
};
int main(void)
{
printf("%d\n", Top); // 0
printf("%d\n", Bottom); // 1
printf("%d\n", Left); // 10
printf("%d\n", Right); // 11
return 0;
}
0
1
10
11
23.4 열거형 만들기
그럼 사용자 정의 열거형을 만들어 보겠습니다.
코드: enumeration_demo.c
#include <stdio.h>
// 우선순위를 묶어서 관리할 수 있는 Priority 열거형 생성
enum Priority
{
High,
Normal,
Low
};
int main(void)
{
enum Priority high = High;
enum Priority normal = Normal;
enum Priority low = Low;
printf("%d, %d, %d\n", high, normal, low);
return 0;
}
0, 1, 2
우선순위를 나타내는 Priority 열거형에 High, Normal, Low의 3가지 항목을 줍니다. Priority high 변수에는High 상수 값을 주는 형태로 Priority 열거형을 사용할 수 있습니다. 열거형 변수의 값을 콘솔에서 정수형으로 출력하면 열거형의 멤버 순서대로 0부터 정수 데이터가 출력됩니다.
23.5 열거형 항목에 상수 값 주기
방향을 나타내는 Align 열거형을 만든다고 가정해 보겠습니다. 다음과 같이 Top, Bottom, Left, Right 항목을 멤버로 줄 수 있습니다.
enum Align
{
Top,
Bottom,
Left,
Right
};
위와 같이 열거형을 선언하면 기본적으로 Align.Top은 0의 값을, Align.Bottom은 1, Align.Left는 2, Align.Right는 3의 상수 값을 가집니다. 만약, 기본값 이외의 값으로 설정하고자 하면 다음 코드 샘플과 같이 각각의 항목에 원하는 값을 지정하면 됩니다.
enum Align
{
Top = 0,
Bottom = 2,
Left = 4,
Right = 8
};
요일에 대한 정보를 열거형으로 관리하면 다음과 같이 선언할 수 있습니다.
enum Weekday
{
Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
};
마찬가지로 커피 사이즈에 대한 열거형은 다음과 같이 선언할 수 있습니다.
enum CoffeeSize
{
Small, Medium, Large
};
이처럼 열거형을 사용하면 여러 개로 이루어진 상수들을 하나의 열거형 이름으로 묶어 관리하기 편합니다.
열거형을 사용하여 요일을 상수화하기
C 언어에서 열거형을 사용하면 서로 연관된 값들을 하나의 자료형으로 정의하여 사용할 수 있습니다. 이번 예제에서는 열거형을 사용하여 요일을 상수화하는 방법을 살펴보겠습니다.
코드: enum_day_of_week.c
#include <stdio.h>
enum DayOfWeek
{
SUNDAY = 0, // 0으로 초기화됨
MONDAY, // 1씩 증가
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY
};
int main(void)
{
printf("%d\n", SUNDAY); // 0
printf("%d\n", MONDAY); // 1
printf("%d\n", TUESDAY); // 2
printf("%d\n", WEDNESDAY); // 3
printf("%d\n", THURSDAY); // 4
printf("%d\n", FRIDAY); // 5
printf("%d\n", SATURDAY); // 6
return 0;
}
0
1
2
3
4
5
6
이 예제에서는 enum
키워드를 사용하여 DayOfWeek
라는 열거형 자료형을 정의하였습니다. SUNDAY
부터 SATURDAY
까지 순서대로 0부터 6까지의 값을 가지도록 초기화를 하였습니다. 따라서 각 상수를 정수형으로 사용할 수 있으며, printf()
함수를 사용하여 값을 출력할 수 있습니다. 출력 결과를 보면, SUNDAY
부터 SATURDAY
까지의 값이 각각 0부터 6까지의 정수로 변환되어 출력되는 것을 확인할 수 있습니다.
23.6 열거형으로 관련있는 항목을 묶어 관리하기
이번에는 열거형을 사용하여 편리하게 여러 항목을 하나의 이름으로 관리하는 내용을 알아보겠습니다.
코드: enum_animal.c
#include <stdio.h>
enum Animal { Mouse, Cow, Tiger };
int main(void)
{
enum Animal animal = Tiger; // 열거형 변수에 열거형 상수 지정
if (animal == Tiger)
{
printf("호랑이\n");
}
return 0;
}
호랑이
열거형을 사용하면 여러 개의 항목을 하나의 이름(Animal)로 관리하여 프로그램 작성할 때 편리함을 제공합니다.
23.7 열거형의 값을 정수형으로 사용하기
열거형의 값을 정수형으로 표현하는 방법을 살펴보겠습니다. 열거형의 각각의 항목은 지정하는 순서대로 0번째 인덱스부터 정수형 값이 저장됩니다. 열거형의 값을 정수형으로 받으면 각각의 인덱스를 반환합니다.
코드: enum_index.c
#include <stdio.h>
enum Animal { Rabbit, Dragon, Snake }; // 0, 1, 2
int main(void)
{
enum Animal animal = Dragon;
int num = animal; // 1
printf("Animal.Dragon: %d\n", num);
return 0;
}
Animal.Dragon: 1
Animal 열거형은 3개의 멤버인 Rabbit, Dragon, Snake를 가집니다. 각각의 멤버는 0, 1, 2의 인덱스 값을 가집니다. 열거형 변수인 animal을 정수형으로 변환하여 출력하면 각각의 멤버가 가지는 인덱스 값이 출력됩니다.
23.8 열거형의 인덱스 순서 변경하기
열거형의 인덱스는 기본값은 0, 1, 2 순서이지만 새로운 값으로 설정할 수 있습니다.
코드: enum_index_change.c
#include <stdio.h>
enum Animal
{
Horse, // 0
Sheep = 5, // 1 => 5
Monkey // 2 => 6
};
int main(void)
{
printf("%d\n", Monkey); // 6
return 0;
}
6
Animal 열거형의 3가지 항목인 Horse, Sheep, Monkey는 기본적으로 0, 1, 2의 값을 가집니다. 만약, Sheep 값을 5로 설정하면 Monkey는 그 다음 값인 6으로 자동 설정됩니다.
23.9 열거형과 switch 문 함께 사용하기
열거형의 값을 비교할 때에는 switch
문을 사용하면 편리합니다.
코드: EnumSwitch.c
enum Animal { Chicken, Dog, Pig }
class EnumSwitch
{
int main(void)
{
Animal animal = Animal.Dog;
switch (animal)
{
case Animal.Chicken:
printf("닭");
break;
case Animal.Dog:
printf("개");
break;
case Animal.Pig:
printf("돼지");
break;
default:
printf("기본값 설정 영역");
break;
}
}
}
}
개
코드 자체로만 봐서는 값을 비교하는 코드가 길어보입니다. 하지만, Visual Studio에서는 열거형의 값을 switch 문에 대입하면 자동으로 열거형의 항목에 해당하는 case 문을 자동으로 만들어주는 기능도 제공하기에 이 역시 프로그래밍의 편리함을 제공해 주는 부분입니다.
C 언어 열거형을 활용한 직업 선택 프로그램 만들기
일상생활에서 다양한 직업군이 존재하며, 각각의 직업은 사회의 다른 부분을 담당하고 있습니다. 이번에는 C 언어의 열거형(enum)을 사용하여 사용자에게 직업을 선택하게 하고, 선택한 직업을 출력하는 간단한 프로그램을 만들어 보겠습니다.
코드: job_selector.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
// Job이라는 이름의 열거형을 정의합니다.
enum Job
{
Developer, // 0
Instructor, // 1
Author // 2
};
int main(void)
{
// myJob이라는 변수를 Job 열거형으로 선언합니다.
enum Job myJob;
// 사용자에게 직업을 선택하도록 안내합니다.
printf("직업을 선택하세요\n");
printf("1. Developer\n");
printf("2. Instructor\n");
printf("3. Author\n");
int choice;
// 사용자로부터 입력을 받아 choice 변수에 저장합니다.
scanf("%d", &choice);
// 사용자의 선택에 따라 myJob 변수에 직업을 할당합니다.
switch (choice)
{
case 1:
myJob = Developer;
break;
case 2:
myJob = Instructor;
break;
case 3:
myJob = Author;
break;
default:
// 잘못된 입력의 경우 안내 메시지를 출력하고 프로그램을 종료합니다.
printf("잘못된 입력입니다.\n");
return 1;
}
// 선택한 직업을 출력합니다.
printf("선택한 직업: ");
switch (myJob)
{
case Developer:
printf("Developer\n");
break;
case Instructor:
printf("Instructor\n");
break;
case Author:
printf("Author\n");
break;
}
return 0;
}
직업을 선택하세요
1. Developer
2. Instructor
3. Author
1
선택한 직업: Developer
직업을 선택하세요
1. Developer
2. Instructor
3. Author
2
선택한 직업: Instructor
직업을 선택하세요
1. Developer
2. Instructor
3. Author
7
잘못된 입력입니다.
위 프로그램은 C 언어의 열거형(enum)을 활용하여 개발자(Developer), 강사(Instructor), 저자(Author)라는 일상적인 직업을 선택하는 예제입니다.
enum Job
은 Developer, Instructor, Author라는 세 가지 직업을 가지고 있습니다.
int main(void)
함수 내부에서는 enum Job
타입의 변수 myJob
을 선언하고, 사용자로부터 직업을 선택하는 입력을 받습니다. 사용자가 입력한 값에 따라 switch
문을 이용하여 myJob
에 해당하는 직업을 할당하고, 선택한 직업을 출력합니다.
잘못된 입력이 들어오면 "잘못된 입력입니다." 라는 메시지를 출력하고 프로그램을 종료합니다. 이 프로그램은 열거형을 이용해 여러 선택사항 중 하나를 선택하고 결과를 출력하는 기본적인 로직을 보여줍니다.
23.10 공용체 선언 및 사용
공용체
C 언어에서 공용체(union)은 같은 메모리 공간을 공유하는 여러 개의 데이터 타입을 저장할 수 있는 데이터 구조입니다.
공용체는 구조체와 마찬가지로 각 데이터 타입에 대한 멤버(member)를 가지며, 하나의 멤버만 저장할 수 있습니다. 즉, 여러 멤버 중 하나만 저장할 수 있습니다.
공용체의 정의는 union 키워드를 사용하여 다음과 같이 작성할 수 있습니다.
union MyUnion {
int x;
float y;
char z;
};
위의 코드에서 MyUnion은 정수 타입의 x, 실수 타입의 y, 문자 타입의 z 멤버를 가집니다.
공용체를 사용하면 메모리 공간을 효율적으로 사용할 수 있습니다. 단, 공용체에 저장된 데이터 타입을 변경할 때는 주의해야 합니다. 각 데이터 타입의 크기가 다를 수 있으므로, 공용체에 저장된 값을 변경할 때 각 데이터 타입의 크기를 고려해야 합니다.
공용체의 멤버에 접근할 때는 다음과 같은 방법을 사용합니다.
union MyUnion u;
u.x = 10;
printf("%d\n", u.x);
위의 코드에서 MyUnion 공용체의 멤버 x에 10을 저장하고, 그 값을 출력합니다.
공용체는 구조체와 마찬가지로 필요에 따라 포인터를 선언하여 사용할 수 있습니다.
union MyUnion *uptr;
uptr = (union MyUnion *) malloc(sizeof(union MyUnion));
uptr->x = 20;
printf("%d\n", uptr->x);
free(uptr);
위의 코드에서 MyUnion 공용체 포인터 uptr을 정의하고, 메모리를 할당하여 x 멤버에 20을 저장하고, 그 값을 출력합니다.
코드: union_demo.c
//[?] 공용체(Union): 구조체와 동일한 기능을 구현하나 메모리를 공용(공유)해서 사용
#include <stdio.h>
// 공용체 선언
union Member
{
char* name;
int age;
double weight;
};
int main(void)
{
// 공용체 형식의 변수 선언
union Member member;
member.name = "홍길동"; // 저장
printf("%s\n", member.name); // 사용
member.age = 21;
printf("%d\n", member.age);
member.weight = 100.05;
printf("%.2f\n", member.weight);
return 0;
}
홍길동
21
100.05
23.11 공용체_공용체사용
코드: 공용체_공용체사용.c
/*
예제. 공용체 사용: 공용체사용.c*** ```C
*/
#include <stdio.h>
union member
{
char* name; // 이름
int age; // 나이
long incom; // 수입
};
int main(void)
{
union member objMember;
objMember.name = "레드플러스";
printf("이름: %s\n", objMember.name);
objMember.age = 21;
printf("나이: %d\n", objMember.age);
objMember.incom = 100000000;
printf("연봉: %ld\n", objMember.incom);
}
이름: 레드플러스
나이: 21
연봉: 100000000
23.12 공용체 크기
코드: 공용체_공용체크기.c
#include <stdio.h>
union UnionType
{
char a;
int b;
double c;
};
int main(void)
{
union UnionType _u;
_u.a = 'A';
printf("%c\n", _u.a);
_u.b = 1234;
printf("%d\n", _u.b);
_u.c*** ```C = 123456789;
printf("%.2f\n", _u.c*** ```C);
printf("공용체 크기: %d\n", sizeof(_u)); // 8
}
A
1234
123456789.00
공용체 크기: 8
23.13 구조체와 공용체의 인스턴스 크기 비교
코드: 공용체_공용체설명.c
#include <stdio.h>
struct StructType
{
char a;
char b;
char c;
};
union UnionType
{
char a;
char b;
char c;
};
int main(void)
{
struct StructType st;
union UnionType ut;
st.a = 'A'; st.b = 'B'; st.c*** ```C = 'C';
ut.a = 'A'; printf("%c\n", ut.a);
ut.c*** ```C = 'B'; printf("%c\n", ut.b);
ut.c*** ```C = 'C'; printf("%c\n", ut.c*** ```C);
printf("구조체 StructType의 인스턴스의 사이즈 : %d\n", sizeof(st));
printf("공용체 UnionType의 인스턴스의 사이즈 : %d\n", sizeof(ut));
}
A
B
C
구조체 StructType의 인스턴스의 사이즈 : 3
공용체 UnionType의 인스턴스의 사이즈 : 1
공용체와 엔디언
엔디언(Endianness)은 데이터를 저장할 때 바이트 단위로 저장하는 순서를 말합니다.
대표적으로 빅 엔디언(Big Endian)과 리틀 엔디언(Little Endian)이 있습니다.
빅 엔디언은 데이터의 가장 앞 바이트부터 저장하는 방식입니다.
반면에 리틀 엔디언은 데이터의 가장 뒷 바이트부터 저장하는 방식입니다. 두 엔디언은 데이터 저장 방식이 다르기 때문에 데이터의 저장 순서가 다릅니다.
엔디언은 프로세서, 운영체제, 네트워크 프로토콜 등에 따라 다릅니다. 예를 들어, 맥의 프로세서는 리틀 엔디언을 사용하지만, 윈도우즈의 프로세서는 빅 엔디언을 사용합니다.
따라서, 엔디언에 대한 고려가 필요한 경우에는 프로그래머가 직접 처리해야 합니다. 예를 들어, 네트워크 프로토콜에서 데이터를 주고 받을 때 엔디언에 맞게 데이터를 저장하거나, 적절한 변환 과정을 거치지 않으면 값이 올바르게 전달되지 않을 수 있습니다.
공용체와 엔디언은 기계어 수준에서의 개념입니다. 공용체는 같은 메모리 공간에 다양한 데이터 타입을 저장할 수 있는 구조체입니다. 엔디언은 데이터를 저장하는 방식을 나타냅니다. 엔디언은 빅 엔디언과 리틀 엔디언으로 나뉘며, 데이터를 가장 앞 바이트부터 저장하는 빅 엔디언과 가장 뒷 바이트부터 저장하는 리틀 엔디언이 있습니다. 이러한 개념은 일반적으로 프로그래밍을 하지 않는 사람에게는 상관없는 개념일 수 있지만, 특정 상황에서는 중요한 개념이 될 수 있습니다.
23.14 장 요약
열거형을 사용하면 변수에 어떤 값이 저장되어야하는지 명확한 값 목록을 제공합니다. 이때 Visual Studio의 인텔리센스 기능으로 해당 목록이 제공되여 편리함을 느낄 수 있습니다. 처음에 열거형을 만드는 수고는 큰 프로그램을 만들 때에 여러모로 도움이 되는 C 언어의 필수 기능입니다. 학습 초반에는 이미 있는 기능들을 위주로 사용하다가 점점 사용자 정의 열거형을 만들어 가면 좋습니다.