[ 공용체 ]
공용체는 구조체와 정의 방법이 같지만 멤버를 저장하는 방식이 다르다. 즉, 다음과 같이 멤버들이 각각 공간을 차지하지만 공용체는 모든 멤버가 공간을 공유한다.

즉, 공용체는 멤버 중에서 가장 큰 자료형의 공간을 공유한다. 현실에서 예를 들자면 물건이 하나 들어있는 선물상자와 비슷하다. 같은 크기의 상자지만 들어있는 물건의 종류가 다른 것 처럼.

공용체 만들고 사용하기
union 공용체이름{
자료형 멤버이름;
};
공용체는 정의만 해서 사용할 수 없고 따로 변수로 선언해서 사용해야한다.
#define _CRT_SECURE_NO_WARNINGS // strcpy 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h>
#inlcude <string.h> // strcpy 함수
union Box{
short candy; // 2바이트
float snack; // 4바이트
char doll[8]; // 8바이트
};
int main(){
union Box b1; // 공용체 변수 선언
printf("%d\n", sizeof(b1)); // 8: 공용체의 전체 크기는 가장 큰 자료형의 크기
strcpy(b1.doll, "bear"); // doll에 문자열 bear 복사
printf("%d\n", b1.candy); // 25954
printf("%f\n", b1.snack); // 4464428256607938511036928229376.000000
printf("%s\n", b1.doll); // bear
return 0;
}
# 실행 결과
8
25954
4464428256607938511036928229376.000000
bear

- printf로
b1.candy,b1.snack,b1.doll의 값을 출력해보면b1.doll은 bear가 정상적으로 출력되지만,b1.candy와b1.snack은 값이 엉망이 되었다. - 구조체와는 달리 공용체는 멤버 중에서 가장 큰 자료형의 공간을 공유한다. 따라서 어느 한 멤버에 값을 저장하면 나머지 멤버의 값은 사용할 수 없는 상태가 된다.
- 그래서 공용체의 멤버는 한 번에 하나씩 쓰면 값을 정상적으로 사용할 수 있다.
- 만약
b1.candy/snack/doll을 구조체로 만들었다면 구조체의 전체크기는 2+4+8 = 14바이트이다. - 공용체로 멤버를 한 번에 하나씩만 쓰는 상황이라면 크기는 8바이트이므로 6바이트 이득인것이다.
- 실무에서는 공용체에 값을 저장할 때 어떤 멤버를 사용할 것인지 미리 정해놓고, 꺼낼때도 정해놓은 멤버에서 값을꺼내는 식으로 사용한다. 즉, 선물 상자 바깥에 어떤 물건이 들어있는지 적어놓고 사용하는 식이다.
=> 정리하자면 공용체는 여러 멤버에 동시에 접근하지 않는 경우 같은 메모리 레이아웃에 멤버를 모아둘 때 사용한다. 특히 공용체는 임베디드 시스템이나 커널모드 디바이스 드라이버 등에서 주로 사용하며 보통은 거의 쓰지않는다.
공용체와 엔디언
#include <stdio.h>
union Data{
char c1;
short num1;
int num2;
};
int main(){
union Data d1; // 공용체 변수 선언
d1.num2 = 0x12345678; // 리틀 엔디언에서는 메모리에 저장될 때 78 56 34 12로 저장됨
printf("0x%x\n", d1.num2); // 0x12345678: 4바이트 전체 값 출력
printf("0x%x\n", d1.num1); // 0x5678: 앞의 2바이트 값만 출력
printf("0x%x\n", d1.c1); // 0x78 앞의 1바이트 값만 출력
printf("%d\n", sizeof(d1)); // 4 : 공용체의 전체 크기는 가장 큰 자료형의 크기
return 0;
}
# 실행 결과
0x12345678
0x5678
0x78
4
printf로 출력해보면
d1.num2는 저장한 숫자가 그대로 나오지만 다른 멤버는 숫자의 일부분만 나온다.공용체는 값을 저장하는 공간은 공유하지만 값을 가져올 때는 해당 자료형의 크기만큼 가져오기 때문이다.
d1.num은 2바이트 크기의short이므로 앞의 2바이트인0x5678만 나온다. 마찬가지로d1.c1은 1바이트 크기의char이므로 1바이트인0x78만 나온다.- 그런데 앞의 값만 나와야 한다면
0x1234와0x12가 나와야 하는데 왜0x5678,0x78이 나올까?
=> 우리가 사용하는
x86(x86-64)계열 CPU는 리틀 엔디언이라는 방법으로 값을 메모리에 저장한다. 간단하게 이야기하면 리틀 엔디어는 숫자를 1바이트씩 쪼개서 낮은 자릿수가 앞에온다. 사람이 보기에는 반대로 뒤집혀있는 것.
- 그런데 앞의 값만 나와야 한다면
0x12345678을 리틀엔디언방식으로 메모리에 저장하면 78 56 34 12가 된다. 공용체는 앞에서부터 자료형의 크기만큼 값을 가져오게 되므로d1.num1은 앞의 2바이트 56 78 을 가져오게 되고,d1.c1은 앞의 1바이트 78만 가져오게 되는 것이다.( 저장할 때 뒤집혀서 저장되었으므로 가져올 때는 다시 되돌려서 가져온다. 따라서 78 56이 아니라 56 78이 된다.)

- 공용체도 구조체와 마찬가지로
typedef로 별칭을 지정하고 익명 공용체를 정의할 수 있따.
typedef union 공용체이름{
자료형 멤버이름;
} 공용체 별칭;
----------------------------------------------------------------------------------------------
typedef union _Box{ // 공용체 이름은 _Box
short candy;
float snack;
char doll[8];
} Box; // typedef을 사용하여 공용체 별칭을 Box로 정의
-----------------------------------------------------------------------------------------------
typedef union { // 익명 공용체 정의
short candy;
float snack;
char doll[8];
} Box; // typedef을 사용하여 공용체 별칭을 Box로 정이ㅡ
Box b1; // 공용체 별칭으로 공용체 변수 선언
------------------------------------------------------------------------------------------------
union Box { // 공용체 정의
short cnady;
float snack;
char doll[8];
} b1; // 공용체를 정의하는 동시에 변수 b1 선언
공용체 포인터를 선언하고 메모리 할당하기
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h> // malloc, free
#include <string.h> // strcpy
union Box{
short candy;
float snack;
char doll[8];
};
int main(){
union Box *b1 = malloc(sizeof(union Box)); // 공용체 포인터 선언, 메모리 할당
printf("%d\n", sizeof(union Box)); // 8: 공용체 전체 크기는 가장 큰 자료형의 크기
strcpy(b1->doll, "bear"); // doll에 문자열 bear 복사
printf("%d\n", b1->candy); // 25954
printf("%f\n", b1->snack); // 4464428256607938511036928229376.000000
printf("%s\n", b1->doll); // bear
free(b1);
return 0;
}
# 실행 결과
8
25954
4464428256607938511036928229376.000000
bear
- 구조체와 마찬가지로 공용체 포인터도 멤버에 접근할 때는
->(화살표 연산자)를 사용한다. typedef로 정의한 공용체 별칭으로도 포인터를 선언하고 메모리를 할당할 수 있다.
typedef union _Box{ // 공용체 이름은 _Box
short candy;
float snack;
char doll[8];
} Box; // typedef를 사용하여 공용체별칭을 Box로 정의
Box *b1 = malloc(sizeof(Box)); // 공용체 포인터 선언, 메모리 할당
- 공용체 포인터에 메모리를 할당하지 않고, 공용체 변수를 그대로 활용할 수도 있다!
union Box{
short candy;
float snack;
char doll[8];
};
int main(){
union Box b1; // 공용체 변수 선언
union Box *ptr; // 공용체 포인터 선언
ptr = &b1; // b1의 메모리 주소를 구하여 ptr에 할당
strcpy(ptr->doll, "bear"); // doll에 문자열 bear 복사
printf("%d\n", ptr->candy); // 25954
printf("%f\n", ptr->snack); // 4464428256607938511036928229376.000000
printf("%s\n", ptr->doll); // bear
return 0;
}'프로그래밍 언어 > [ C ]' 카테고리의 다른 글
| [ C ] 17. 연결리스트 구조체 ( Linked List ) (0) | 2020.11.30 |
|---|---|
| [ C ] 16. volatile 이용하기 (0) | 2020.08.27 |
| [ C ] 14. goto에 관하여 (0) | 2020.08.14 |
| [ C ] 13. 함수 포인터 배열 활용하기 (0) | 2020.08.14 |
| [ C ] 12. 함수와 가변인자 (0) | 2020.08.14 |