내용 참고
YES C (정보공학연구소/생능출판사)
혼자 연구하는 C/C++ (Soen.kr/와우북스)
Microsoft Docs (구 MSDN)
C언어 이론 15 / 사용자 정의 자료형 2) 공용체
Ⅱ. 공용체
■ 공용체는 같은 메모리 공간을 공유하는 변수들을 묶어놓은 것이다.
ⅰ. 공용체의 선언
■ 공용체를 선언할 때는 'union' 키워드를 사용한다.
■ 공용체를 선언하는 방법은 구조체를 선언할 때와 완전히 동일하다.
■ 즉, 4가지의 구조체 선언방법을 공용체에도 똑같이 적용할 수 있다.
■ 이렇게 선언한 공용체의 이름은 하나의 타입처럼 취급된다.
ⅱ. 공용체의 특징
1. 메모리를 공유한다.
■ 공용체의 가장 큰 특징은 멤버들끼리 같은 공간(=메모리)를 공유한다는 것이다.
■ 아래와 같은 상황에서 구조체는 적어도 멤버들의 크기를 모두 더한것보다 큰 크기를 갖는다. (아래의 경우 최소 13byte)
■ 하지만 공용체의 경우 가장 크기가 큰 멤버의 크기를 기준으로 크기를 갖는다. (아래의 경우 최소 8byte)
■ 다만 정확하게 메모리가 할당되는 것은 운영체제나 하드웨어에 따라 다를 수 있다.
2. 값이 오염될 수 있다.
■ 멤버들끼리 같은 메모리를 공유한다는 것은 1번 멤버의 값을 바꾸면 2번 멤버의 값도 바뀐다는 뜻이다.
■ 즉, 공용체를 사용하면 메모리를 아낄 수는 있지만 값이 오염될 수 있다.
■ 그렇기 때문에 공용체는 매우 특수한 경우에만 사용된다.
ⅲ. 공용체의 초기화와 기본값 설정
■ 공용체는 멤버들간에 값을 공유하기 때문에 초기화할 때 값을 하나만 넣어야 한다.
■ 이는 기본값을 설정할 때도 마찬가지이다.
ⅳ. 공용체를 사용하는 경우
1. 메모리를 극도로 절약해야 할 때
■ 공존할 수 없거나, 공존할 필요가 없는 값들을 공용체로 묶어서 선언하면 메모리를 절약할 수 있다.
■ 하지만 메모리가 충분한 상황에서 억지로 공용체를 사용하는 것은 득보다는 실이 많기 때문에 추천되지 않는다.
2. 커다란 데이터를 쪼개서 확인할 필요가 있을 때
■ 예를 들어 1byte(=8bit)의 값을 1bit씩 쪼개서 확인하고 싶다면 다음과 같은 코드를 사용할 수 있다.
#include <iostream>
union data {
struct bit {
bool _0 : 1; // LSB
bool _1 : 1;
bool _2 : 1;
bool _3 : 1;
bool _4 : 1;
bool _5 : 1;
bool _6 : 1;
bool _7 : 1; // MSB
} d;
char value;
};
int main(void) {
data t;
scanf("%d",(int*)(&t.value));
printf("%d%d%d%d %d%d%d%d\n",
t.d._7, t.d._6, t.d._5, t.d._4,
t.d._3, t.d._2, t.d._1, t.d._0);
return 0;
}
■ 위의 코드를 사용하면 0~255까지의 숫자를 이진수로 확인할 수 있다.
■ 참고로 출력을 _0부터가 아니라 _7부터 하고 있는데 이는 리틀 엔디안 방식을 사용하고 있는 경우를 가정한 것이다.
■ 빅 엔디안과 리틀 엔디안에 대한 자세한 설명은 추후에 다룰 예정이다.
3. 나눠진 데이터를 묶어서 다루고 싶을 때
■ 위와는 반대의 경우로 4개로 숫자로 이루어진 ip주소를 예로 들수 있다.
#include <stdio.h>
union tag_ip {
unsigned char addr[4];
unsigned long ip;
};
int main()
{
tag_ip a;
scanf("%d.%d.%d.%d",(int*)(&a.addr[0]),(int*)(&a.addr[1]),(int*)(&a.addr[2]),(int*)(&a.addr[3]));
printf("ip : %ld \n", a.ip);
printf("%d.%d.%d.%d",a.addr[0],a.addr[1],a.addr[2],a.addr[3]);
return 0;
}
■ 입력 자체는 4개의 숫자를 따로 따로 받지만 실제 사용은 하나로 묶어서 사용하는 경우이다.