Quick Reference
union은 모든 멤버가 같은 저장 공간을 공유하므로 한 시점에 의미 있는 값은 보통 하나입니다. 현재 멤버를 tag로 함께 관리하는 tagged union을 기본 형태로 둡니다.
typedef enum { VALUE_INT, VALUE_FLOAT } ValueKind;
typedef struct {
ValueKind kind;
union {
int i;
float f;
} data;
} Value;
Value value = { .kind = VALUE_INT, .data.i = 42 };
if (value.kind == VALUE_INT) {
printf("%d\n", value.data.i);
}동시에 필요한 필드는 struct에 둡니다. union은 tag가 가리키는 active member만 읽고, 포인터 variant로 바꾸기 전에는 이전 variant의 소유 자원을 먼저 정리합니다.
문법
union은 모든 멤버가 같은 시작 주소를 공유합니다. 그래서 struct처럼 여러 필드가 동시에 존재하는 구조가 아닙니다.
union Value {
int i;
float f;
char bytes[4];
};실전에서는 보통 현재 활성 멤버를 알려 주는 태그를 같이 둡니다.
typedef enum {
VAL_INT,
VAL_FLOAT,
VAL_STRING
} ValueType;
typedef struct {
ValueType type;
union {
int i;
float f;
const char *s;
} data;
} Value;이 패턴의 핵심은 type이 "현재 무엇이 들어 있는가"를 알려준다는 점입니다.
문자열 포인터 payload를 넣는다면 tag만 바꾸는 것으로 소유권이 해결되지는 않습니다. 누가 문자열을 할당·해제하는지, 다른 variant로 바꾸기 전에 기존 payload를 정리하는지를 tagged union의 생성·파괴 함수에 함께 둡니다.
갈리는 기준
- 동시에 여러 필드가 모두 필요하면
struct - 여러 타입 중 하나만 필요하면
union
즉 union의 핵심 이유는 메모리 공유입니다. 단순히 타입을 묶고 싶다는 이유만으로는 보통 struct가 더 자연스럽습니다.
한 멤버에 쓴 비트 패턴을 다른 멤버로 읽어 범용 형변환을 하려는 type punning은 이식 가능한 변환 방법이 아닙니다. 비트 표현이 필요하면 memcpy와 명시적인 폭·byte order 규칙을 사용합니다.
빠른 점검
union은 여러 멤버가 같은 메모리 시작 위치를 공유합니다.- 한 시점에 의미 있는 멤버는 보통 하나입니다.
- 현재 유효한 멤버를 코드가 어떻게 보장하는지 같이 봐야 합니다.
- 실전에서는
enum + union형태의 tagged union이 가장 안전한 패턴입니다. - 동시에 여러 필드가 다 필요하면
struct가 맞습니다.
주의할 점
union은 메모리를 아끼는 대신 상태 추적 책임을 개발자에게 넘깁니다. 어떤 멤버가 현재 유효한지 코드로 보장되지 않으면, 읽는 쪽이 조용히 잘못된 해석을 하게 됩니다.
참고 링크
2 sources