공용체는 구조체와 같은 새로운 DataType을 선언하는 것입니다. 근데 아주 결정적인 차이점을 가지고 있습니다. 구조체는 변수 선언에 따라 멤버변수 전체의 공간만큼 할당을 받습니다. 예를 들면, 구조체 안에 int형 변수 2개에 char형 변수 1개가 있다면, 총 9Byte만큼을 메모리공간에 할당받습니다.
하지만, 공용체는 멤버변수중 가장 크게 할당받는 자료형만큼 할당받습니다. 만약 int형 1개 double형 1개를 만든다면 double형 1개만큼인 8byte만큼 할당받고, 그 8byte를 다른 멤버변수와 공용하여 사용합니다.
간단하게 공용체의 선언과 사용에 대해서 알아보겠습니다. 일단 예시 하나 보면서 설명하겠습니다.
예시
union test {
int value;
char text[4];
};
int main() {
union test a;
a.value = 0x12345678;
printf("%x%x%x%x\n", a.text[0], a.text[1], a.text[2], a.text[3]);
return 0;
}
결과
78563412
먼저 union이기 때문에 value와 text[4]가 같은 메모리공간에 4byte만큼 할당받는다는 것을 알수 있습니다. 따라서 value에 0x12345678이라는 값을 넣고, 이것을 text의 1byte씩 쪼개지게 되면 메모리공간에는 밑에 그림처럼 바뀌게 됩니다.

따라서 text[0] 부터 text[3]까지 출력하면 78563412가 나오게 되는 것입니다.
구조체에는 비트단위로 공간을 할당할 수 있는데, 그것을 구조체 비트필드라고 합니다. 근데 왜 공용체에 구조체 비트필드가 나오나요? 라고 한다면, 둘이 엄청나게 유사한 성격을 가지고있습니다. 물론 할당받은 공간을 공용으로 사용하지는 않지만, 공간이 부족하지 않다면, 가장 큰 DataType의 크기만큼만 공간을 할당받기 때문입니다.
예시
struct Flags {
unsigned int a : 1; // a는 1비트 크기
unsigned int b : 3; // b는 3비트 크기
unsigned int c : 7; // c는 7비트 크기
};
여기서 Flags의 크기는 unsigned int형인 4byte입니다. 총 11비트를 사용합니다. 하지만 11비트는 3byte보다 작기 때문에, 4byte 1개만으로 충분하기 때문에, 효율적으로 할당받습니다. 공용체와 아주 유사한 성격을 가졌습니다.
그럼 공용체와 구조체 비트필드를 합친 예제를 보겠습니다. 여기서 bitPrint라는 함수가 나옵니다. 앞에서 배웠던 bit연산자가 나오기 때문에, 비트연산자를 한번씩 다시 보시는 것을 추천드립니다.
예시
#include <stdio.h>
struct Color { // 구조체 비트필드
unsigned short red : 5;
unsigned short green : 6;
unsigned short blue : 5;
};
void bitPrint(unsigned short value) {
int mask = 1;
int count = sizeof(unsigned short) * 8;
count--;
int output = 0;
while (count >= 0) {
mask = mask << count;
printf("%d", value & mask ? 1 : 0);
mask = 1;
if (count % 8 == 0) {
printf(" ");
}
count--;
}
}
int main() {
struct Color color;
color.red = 1;
color.green = 2;
color.blue = 3;
union uColor {
struct Color color;
unsigned short value;
};
union uColor value;
value.color = color;
bitPrint(value.value);
return 0;
}
결과
00011000 01000001
결과가 띄어쓰기 빼고 0001100001000001 입니다. 여기서 비트단위로 쪼개본다면 00011/000010/00001입니다. 2진수를 10진수로 바꾸면, 3/2/1이 됩니다.