공용체 (union)/ 에디안 방식 / 열거형 (enum)
사실 공용체(union)은 그리 많이 사용하는 기능은 아니다. 그래도 C 언어에서 제공하는 것들 중 하나이니까 살펴보자. 공용체는 구조체와는 달리 메모리를 '공유' 한다.
위 그림을 보아도 알 수 있듯이 공용체는 멤버들의 시작 주소가 동일하다. 따라서 j
의 값을 변경함으로써 i
의 값을 변경할 수 있고, i
의 값을 변경함으로써 j
의 값을 변경할 수 있다. 한번 실제로 그런지 확인해보자.
#include <stdio.h>
union A {
int i;
char j;
};
int main() {
union A a;
a.i = 0x12345678;
printf("%x", a.j);
return 0;
}
실행 결과
78
우리가 j
의 값을 전혀 설정해주지 않았는데도 i
에 0x12345678
를 대입하니까 78 이라는 값이 나온다. 그런데 왜 78이 나왔을까? 0x12
가 나와야 하는게 아닌가? 분명 i
와 j
의 시작 주소는 동일하다. i
가 0x12345678
로 메모리상에 있다면 j
의 처음 두 개인 0x12
가 되어야 할 것 같은데 말이다. 물론, 우리가 생각하는게 맞다. 그러나 컴퓨터는 수를 이렇게 보관하지 않는다.
빅 에디안(Big Endian) / 리틀 에디안(Little Endian)
컴퓨터에 수를 보관할 때 우리가 생각하는 방법, 즉 낮은 주소값에 상위 비트를 적는 방식을 빅 에디안 방식이라고 한다. 그리고, 우리가 생각하는 방식의 반대로 높은 주소값의 상위 비트를 적는 방식을 리틀 에디안 방식이라고 한다. 현재 대부분의 x86
프로세서는 리틀 에디안 방식을 사용한다. 일부 컴퓨터에서만 빅 에디안 방식을 사용한다.
먼저 빅 에디안 방식이 어떻게 수를 보관하는지 보자
이와 같이 상식적으로 수가 저장 된다. 하지만 이건 빅 에디안 방식이다. 우리가 대부분 사용하는 리틀 에디안은 다음과 같다.
이와 같이 1 바이트 씩 역으로 보관 된다. 따라서 우리가 j
를 출력하면 0x78
이 출력된다. 그렇다면 만약 우리가 j
를 int
형이 아니라 shor
형으로 선언했다면 과연 0x7856
이 나올까 아니면 0x5678
이 나올까??
#include <stdio.h>
union A {
int i;
short j;
};
int main() {
union A a;
a.i = 0x12345678;
printf("%x\n", a.j);
return 0;
}
실행 결과
5678
이번에는 0x5678
이 나온다. 여기서 혼란이 온다.. 메모리 상에 그대로 살펴보면 분명히 j
에 해당하는 부분은 0x7856
이 출력되어야 정상이지만 컴퓨터는 '지극히 정상적으로 0x5678
을 출력하였다. 왜 그럴까? 이유는 간단하다.
이번에는 j
가 short
형 (2 바이트) 이기 때문에 j
가 2 바이트를 차지하게 된다. 그런데 j
를 출력해보면 0x7856
이 아니고 0x5678
이 출력된다. 왜 그럴지 고민하고 있을 때 누군가 이러한 질문을 던졌다.
"
i
의 값을 출력하면 얼마나 나올까?"
당연히 0x12345678
이 나오겠지. 라고 생각했을 것이다. 왜?? , 컴퓨터는 자신이 메모리에 수를 저장하는 방식이 리틀 에디안 방식이라는 것을 알고 있기 때문에 출력시에는 이를 적절하게 변환을 취해서 0x12345678
을 출력할 것이다.
j
의 경우도 마찬가지이다. j
는 현재 '78 56' 부분을 가리키고 있지만 컴퓨터는 j
가 리틀 에디안 형식으로 이루어져 있다는 것을 알기 때문에 j
를 출력할 때 이를 적절히 변환을 취해서 0x5678
로 바꿔서 출력하게 된다.
여기서 구조체는 끝내겠다. 구조체는 잘 사용하지 않지만 한번쯤은 듣게 될 것이다. 구조체 보다 더 중요한 것은 에디안이다. 에디안에 대해서는 까먹지 않도록 공부하자.
열거형 (Enum)
프로그램밍을 하다가 보면 데이터를 수에 대응 시키는 경우가 많이 생긴다. 예를 들어서 남자는 1, 여자는 0에 대응시키거나 흰색은 0, 검은색은 1 에 대응시켜서 나타내게 된다. 그런데 이렇게 수를 대응해서 나타내면 다음과 같이 헷갈리는 경우가 발생한다.
if (human.gender == 0) // 사람의 성별이 0 일 때
남자는 0, 여자는 1 임을 확실히 기억하고 있다면 상관이 없지만 기억을 못하게 된다면 성에 대해서 무엇을 대응 시켰는지 다시 찾아봐야 하는 번거로운 일이 발생하게 된다. 하지만 아래와 같이
if (human.gender == MALE) // 사람의 성별이 남자 일 때
를 한다면 확실히 알아 듣기 쉬울 것이다. 하지만 문제는 MALE
이라는 상수를 설정해야 하고 이 때문에 메모리 공간 또한 낭비된다. 이는 프로그래머 입장에서 상당히 난처하다. 따라서 C 에서는 열거형 (Enum) 을 도입하여 이러한 문제를 깔끔하게 해결하였다.
#include <stdio.h>
enum { RED, BLUE, WHITE, BLACK };
int main() {
int palette = RED;
switch (palette) {
case RED:
printf("palette : RED \n");
break;
case BLUE:
printf("palette : BLUE \n");
break;
case WHITE:
printf("palette : WHITE \n");
break;
case BLACK:
printf("palette : BLACK \n");
break;
}
}
실행 결과
palette : RED
여기선 다음 부분만 살펴보자
enum { RED, BLUE, WHITE, BLACK };
열거형을 나타내기 위해 enum
을 사용하고 중괄호 안에 각각에 대해 써주면 된다. 그렇다면 컴파일러는 열거형에 나타나 있는 각 원소에 0부터 차례대로 정수값을 매겨준다. 즉, RED = 0, BLUE = 1, WHITE = 2, BLACK = 3
이와 같이 말이다. 이제 우린 이것들을 자유롭게 이용하면 된다.
예를 들어서
if (palette == 0) // 현재 파레트의 색이 빨강인지 확인한다.
를
if (palette == RED) // 현재 파레트의 색이 빨강인지 확인한다.
로 바꿔서 사용해도 된다는 것이다. 사실 위의 의미는 정확하게 동일하지만, 프로그래머가 읽을 때는 큰 차이가 있는 것이다. 위와 같이 한다고 해서 메모리 상에 RED
라는 변수가 정해지는게 아니다. 컴파일시에 컴파일러는 RED
는 모두 0으로 바꾸고 BLUE
는 모두 1로 바꾸는 등의 변환 작업을 하게 된다.
열거형 팁
#include <stdio.h>
enum { RED = 3, BLUE, WHITE, BLACK };
int main() {
int palette = BLACK;
printf("%d \n", palette);
}
실행 결과
6
열거형의 처음 수를 0부터 시작하기 싫다면 단순히 원하는 숫자를 위와 같이 해주면 된다. 그러면 RED
는 3이 되고 그 뒤로는 순서대로 4 , 5, 6 이 된다. 또한
enum { RED = 3, BLUE, WHITE = 3, BLACK }
으로 한다면 수를 지정한 부분부터 다시 시작하는 방식으로 BLUE = 4, BLACK = 4
가 된다. 참고로 열거형은 언제나 정수형이여야 한다.
Author And Source
이 문제에 관하여(공용체 (union)/ 에디안 방식 / 열거형 (enum)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@jhon3242/공용체-union-에디안-방식저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)