54.1 공용체를 만들고 사용하기

이제 공용체를 만들어보겠습니다. 공용체는 union 키워드를 사용하여 정의합니다.

union 공용체이름 {
    자료형 멤버이름;
};

공용체는 정의만 해서는 사용을 할 수가 없습니다. 따라서 공용체도 변수로 선언해서 사용합니다.

  • union 공용체이름 변수이름;

다음 내용을 소스 코드 편집 창에 입력한 뒤 실행해보세요.

union.c

#define _CRT_SECURE_NO_WARNINGS    // strcpy 보안 경고로 인한 컴파일 에러 방지
#include <stdio.h>
#include <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

먼저 union 키워드 뒤에 공용체 이름을 지정해주고 { }(중괄호) 안에 변수를 선언해줍니다. 그리고 공용체를 정의할 때 } (닫는 중괄호) 뒤에는 반드시 ; (세미콜론)을 붙여줍니다.

union Box {    // 공용체 정의
    short candy;     // 2바이트
    float snack;     // 4바이트
    char doll[8];    // 8바이트
};

공용체는 보통 main 함수 바깥에 정의합니다. 만약 함수 안에서 공용체를 정의하면 해당 함수 안에서만 공용체를 사용할 수 있습니다.

정의한 공용체를 사용하려면 공용체 변수를 선언해야 합니다. 이때는 공용체 이름 앞에 반드시 union 키워드를 붙여줍니다. 다음은 Box 공용체 타입의 변수 b1을 선언한다는 뜻입니다.

union Box b1;    // 공용체 변수 선언

이제 sizeof로 공용체의 크기를 구해보겠습니다. Box 공용체의 크기는 얼마가 나올까요?

  • sizeof(union 공용체)
  • sizeof(공용체변수)
  • sizeof 공용체변수

Box 공용체의 멤버 short candy는 2바이트, float snack은 4바이트, char doll[8]은 8바이트입니다. 따라서 가장 큰 자료형이 char 8개 크기의 배열이므로 공용체의 전체 크기는 8입니다.

printf("%d\n", sizeof(b1));  // 8: 공용체의 전체 크기는 가장 큰 자료형의 크기
그림 54‑3 공용체의 전체 크기

이제 공용체의 멤버에 접근해보겠습니다. 다음과 같이 일반 변수로 선언한 공용체의 멤버에 접근할 때는 . (점)을 사용합니다. 여기서는 b1.doll에 문자열 "bear"를 복사했습니다.

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

printfb1.candy, b1.snack, b1.doll의 값을 출력해보면 b1.doll"bear"가 정상적으로 출력되지만 b1.candy, b1.snack은 값이 엉망이 되었습니다. 구조체와는 달리 공용체는 멤버 중에서 가장 큰 자료형의 공간을 공유합니다. 따라서 어느 한 멤버에 값을 저장하면 나머지 멤버의 값은 사용할 수 없는 상태가 됩니다.

그래서 공용체의 멤버는 한 번에 하나씩 쓰면 값을 정상적으로 사용할 수 있습니다.

b1.candy = 10;
printf("%d\n", b1.candy);    // 10: 사용(출력)

b1.snack = 60000.0f;
printf("%f\n", b1.snack);    // 60000.00000000: 사용(출력)

strcpy(b1.doll, "bear");
printf("%s\n", b1.doll);     // bear: 사용(출력)

만약 b1.candy, b1.snack, b1.doll을 구조체로 만들었다면 구조체의 전체 크기는 2 + 4 + 8 = 14바이트입니다(구조체 멤버 정렬이 되면 16바이트). 공용체로 멤버를 한 번에 하나씩만 쓰는 상황이라면 크기는 8바이트이므로 6바이트 이득입니다.

실무에서는 공용체에 값을 저장할 때 어떤 멤버를 사용할 것인지 미리 정해놓고, 꺼낼 때도 정해놓은 멤버에서 값을 꺼내는 식으로 사용합니다. 즉, 선물상자 바깥에 어떤 물건이 들어있는지 적어놓고 사용하는 식이죠.

정리하자면 공용체는 여러 멤버에 동시에 접근하지 않는 경우 같은 메모리 레이아웃에 멤버를 모아둘 때 사용합니다. 특히 공용체는 임베디드 시스템이나 커널 모드 디바이스 드라이버 등에서 주로 사용하며 보통은 거의 쓰지 않습니다. 그래서 공용체는 그냥 잊어버려도 되고, 필요할 때 이 책으로 돌아와서 공용체를 복습하면 됩니다.