C의 union
union은 struct와 문법이 거의 비슷하다.
typedef struct s_my_struct
{
int foo;
float bar;
} t_my_struct;
typedef union u_my_union
{
int foo;
float bar;
} t_my_union;
C
복사
struct와 union 예시
struct는 모든 멤버를 포함하는 데 반해 union은 멤버 중 하나만 포함한다.
위 예시에서 struct는 foo와 bar를 각각 저장할 수 있는데, union은 둘 중 하나만 저장할 수 있다.
그 이유는 union의 모든 멤버는 같은 메모리 공간을 공유하기 때문이다.
struct는 모든 멤버 크기를 합한 만큼 공간을 차지하는 데 반해, union은 제일 큰 멤버만큼만 차지한다.
Union의 사용처
union만 갖고 할 수 있는 것은 그다지 많지 않아 보인다.
t_my_union 타입의 변수가 있어도, 이게 foo를 담고 있는지 bar를 담고 있는지 모르기 때문이다.
같은 데이터에 대한 다른 표현
예를 들면 같은 색상 데이터를 색상 코드나 byte 배열, 또는 구조체로 나타낼 수 있겠다.
typedef struct s_s_color
{
uint8_t alpha;
uint8_t red;
uint8_t green;
uint8_t blue;
} t_s_color;
typedef union u_color
{
uint32_t code;
uint8_t array[4];
t_s_color argb;
} t_color;
C
복사
색상을 union으로 표현한 예시
하지만 이 예시에는 큰 결함이 있는데, 바로 엔디언이다.
0xFF440088에서 FF가 과연 alpha에 들어갈까? 리틀 엔디언에서는 blue에 들어갈 것이다.
reinterpret_cast
float u32_to_float(uint32_t u)
{
union s_u32_or_float
{
uint32_t u;
float f;
} a;
a.u = u;
return (a.f);
}
C
복사
uint32_t를 받아 같은 비트열을 가진 float을 반환하는 함수 예시
uint32_t와 float이 모두 32비트라는 것을 알고 있으므로 uint32_t를 받아 그와 같은 비트열로 이루어진 float으로 바꾸거나, 그 역이 가능하다.
하지만 이는 union을 사용하지 않고도 가능하다.
float float_to_u32(float f)
{
return (*((uint32_t *)&f));
}
C
복사
선택적 변수
void print(t_my_union u, bool is_foo)
{
if (is_foo)
printf("%d\n", u.foo);
else
printf("%f\n", u.bar);
}
C
복사
union 사용 예시
어떤 조건에 따라 어떤 멤버로 사용해야 할지 결정될 때가 있다. 사실 거의 항상 그렇다.
그런 경우 union과 함께 그 union을 어떻게 해석해야 할지, 그 타입 정보를 같이 전달할 수 있다.
하지만 이렇게 쓸 거라면 union과 타입 정보를 같이 전달하는 것이 낫지 않을까?
Tagged Union
그래서 등장한 것이 tagged union이다.
union과 그 union을 어떤 멤버로 해석해야 할지를 저장하는 enum을 한데 묶은 것이다.
typedef enum e_my_union_type
{
MY_UNION_TYPE_A,
MY_UNION_TYPE_B,
MY_UNION_TYPE_C,
} t_my_union_type;
// t_my_type_a, t_my_type_b, t_my_type_c
typedef union u_my_union_value
{
t_my_type_a a;
t_my_type_b b;
t_my_type_c c;
} t_my_union_value;
typedef struct s_my_union
{
t_my_union_type type;
t_my_union_value value;
} t_my_union;
C
복사
union과 type을 struct로 묶은 tagged union 예시
typedef enum e_my_union_type
{
MY_UNION_TYPE_A,
MY_UNION_TYPE_B,
MY_UNION_TYPE_C,
} t_my_union_type;
typedef struct s_my_union_a
{
t_my_union_type type;
// ... a
} a;
typedef struct s_my_union_b
{
t_my_union_type type;
// ... b
} b;
typedef struct s_my_union_c
{
t_my_union_type type;
// ... c
} c;
typedef union u_my_union
{
t_my_union_type type;
t_my_union_a a;
t_my_union_b b;
t_my_union_c c;
} t_my_union;
C
복사
type으로 시작하는 struct를 union으로 묶은 tagged union 예시
위 예시를 포함해 여러가지 유형으로 나타날 수 있는데, 이들 모두 tagged union이다.