본문으로 바로가기
homeimage
  1. Home
  2. 컴퓨터/프로그래밍
  3. C언어 공용체 union 예제 설명

C언어 공용체 union 예제 설명

· 댓글개 · 바다야크

C언어 union 유니온 공용체 예제 설명

포인터 때문에 C언어 배우기가 어렵다는 말씀을 자주 듣는데요, 생각 외로 공용체 union를 이해하지 못하는 분이 많네요. 이해한다고 해도 어디에 활용할지 몰라서 사용하지 않는 경우도 많은데요, struct만큼이나 매우 유용합니다. union의 쓰임새를 깨닫고 코드에 적용하다 보면 왜 C언어가 어셈블러에 가깝다는 얘기가 나오는지 이해가 될 것입니다.

C언어의 변수 타입은 문자·숫자·문자열로 특성에 맞추어 선언한다기보다는 변수의 크기를 정하는 쪽에 가깝습니다. 아울러 이렇게 생각하는 것이 C언어 코딩에 도움이 큽니다. 예를 들어 int는 정수 변수이기도 하지만, 4바이트의 변수로, char는 문자보다는 1바이트 크기의 변수로 생각한다면 C언어에서 변수 다루기가 편해지고 포인터의 이해도 높일 수 있습니다.

이렇게 변수는 변수 형에 따라 바이트 단위의 고정된 크기를 갖습니다. 그리고 여러 개의 바이트로 구성된 한 개의 변수를 다른 크기의 변수로 쪼갤 때 공용체(union)를 사용합니다.

예를 들어 4바이트 크기의 int num 변수에서 하위 1바이트의 값만 가지고 오고 싶다면 num & 0xff 식으로 비트 연산을 합니다. 하위 두 번째 바이트만 가져오려면 0xff00 으로 and 연산을 한 다음 비트를 오른쪽으로 shift 하겠죠?

그러나 공용체(union)를 사용하면 매우 간단해집니다. int num에 char 변수 a를 공용체(union)로 묶으면 int num의 최하위 바이트와 char a 변수는 같은 위치로 묶입니다.

union union_t {
   int     num;
   char  a; 
}

위 union_t의 전체 바이트 개수는 몇 개일까요? 정답은 4바이트입니다. 가장 큰 변수인 int num을 메모리에 할당한 후 char a 변수를 num의 메모리 일부분에 할당합니다.

▲ 그림으로 표현하면 이런 모습으로 변수는 두 개이지만, 같은 메모리를 함께 사용하게 됩니다. 그래서 이름을 공용체라고 합니다. 리틀엔디안 시스템에서 num의 하위 바이트는 char a와 같은 메모리를 공유합니다.

union union_t un;
un.num  = 0x01;
un.a      = 0x02;
printf( "un.num=%x\n", un.num);

un.num의 값은 무엇일까요? 메모리 배치에 따라 un.a는 un.num과 같은 메모리이므로 2가 됩니다. 이번에는 아래와 같이 선언했다면 어떨까요?

union union_t{
   int   num;
   char  a;
   char  b;
   char  c;
   char  d;
}

▲ 위의 그림처럼 char a, b, c, d가 int num의 영역을 사이좋게 나누어서 배치될까요?

▲ 그러나 예상과는 달리 모두 같은 서열로 묶이므로 결과적으로 위의 모습처럼 메모리에 할당됩니다.

union union_t un;

un.num  = 0x01;
un.a    = 0x02;
un.b    = 0x03;
un.c    = 0x04;
un.d    = 0x05;

printf( "un.num=%x\n", un.num);

공용체를 이해하셨다면 printf()로 출력되는 값을 예상할 수 있을 것입니다. 답은? 0x05

union은 struct와 조합해야 유용

그렇다면 char a, b, c, d가 int num의 영역을 바이트 단위로 배치할 수 있을까요? struct를 이용하면 됩니다.

#include <stdio.h>

union union_t{
   int     num;
   struct {
      char  a;
      char  b;
      char  c;
      char  d;
   };
};  

int main( void){
   union union_t union_num;
   union_num.a = 0x01;
   union_num.b = 0x02;
   union_num.c = 0x03;
   union_num.d = 0x04;
   
   printf( "%x\n", union_num.num);
   return 0;
}

프로그램 실행 결과는,

$ ./a.out
4030201
$

struct로 char a, b, c, d가 하나로 묶여서 바이트 4개짜리 변수가 됩니다. 그러므로 int num의 4개 바이트 메모리 영역을 차례로 차지하게 됩니다. 특히, 비트 처리할 때 매우 편합니다.

#include <stdio.h>

union union_t{
   unsigned char byte;
   struct {
      unsigned int bit_0 :1;
      unsigned int bit_1 :1;
      unsigned int bit_2 :1;
      unsigned int bit_3 :1;
      unsigned int bit_4 :1;
      unsigned int bit_5 :1;
      unsigned int bit_6 :1;
      unsigned int bit_7 :1;
      };
   };
   
int main( void) {
   union union_t union_num;
   union_num.byte = 0x95;
   
   printf( "%d\n", union_num.bit_0);
   printf( "%d\n", union_num.bit_1);
   printf( "%d\n", union_num.bit_2);     
   printf( "%d\n", union_num.bit_3);    
   printf( "%d\n", union_num.bit_4);    
   printf( "%d\n", union_num.bit_5);    
   printf( "%d\n", union_num.bit_6);   
   printf( "%d\n", union_num.bit_7);   
   return 0;
}

위 예처럼 바이트를 비트 단위로 값을 확인할 수 있고 변경할 수 있습니다. 실행 결과는 아래와 같습니다.

$ ./a.out
1
0
1
0
1
0
0
1
$

비트 연산보다도 훨씬 이해하기 쉬운 코드를 작성할 수 있습니다.

SNS 공유하기
💬 댓글 개
최근글
이모티콘창 닫기
울음
안녕
감사해요
당황
피폐

이모티콘을 클릭하면 댓글창에 입력됩니다.