강좌 & 팁
C 언어를 사용하신다면 struct는 아마도 대부분 사용하실 것이라고 생각됩니다. 그런데 의외로 사용하지 않는 것이 있는데 바로 union입니다. 흠~ 이유가 뭘까? 아마도 struct 보다는 사용하는 경우의 수가 적기 때문이 아닐까 생각합니다. 그런데 문제는 사용할 꺼리가 적다 보니 잊혀져 버리는 것 같아요. 아무리 멋진 자동차도 쳐다 보지 않고 내팽게쳐 준다면 녹이 슬고 말겠죠.
union이 그런 것이 아닐까 생각됩니다. 사용하면 편한데, 사용하는 경우가 적다 보니 잊혀져서 사용하지 못하는. 그러나 아예 잊혀지기 전에 잠시 둘러 보죠.
저 같은 겨우 union을 시리얼 통신이나 TCP/IP 통신에서 가끔 사용합니다. 혹시, 이런 경우 있지 않나요? 시리얼로 한 바이트씩 정수 값을 받아 들이는 경우 말이죠.
- 상대방이 보내려는 정수 값 : 0x12345678
- 상대방이 하나 씩 보낸 순서 : 0x12, 0x34, 0x56, 0x78
이럴 때 union을 사용하면 편한데, 대부분 버퍼로 받아서는 직접 계산을 하더군요.
n_size = buff[3] * 256 * 256 * 256 + buff[2] * 256 * 256 + buff[1] * 256 + buff[0]
또는 비트를 shift 하기도 하지만, 어찌되었든 같은 방법입니다. 그러나 union을 사용하면 매우 간단해 집니다.
#include <stdio.h> typedef unsigned char byte; typedef unsigned int u32; typedef struct { byte b1, b2, b3, b4; } size_byte_t; typedef union { u32 size; size_byte_t bytes; } size_data_t; int main( void){ size_data_t s_size; // 시리얼로 4개의 바이트를 buff[]로 받았다면 s_size.bytes.b1 = buff[0]; s_size.bytes.b2 = buff[1]; s_size.bytes.b3 = buff[2]; s_size.bytes.b4 = buff[3]; printf( "data size =%x\n", s_size.size); return 0; }
struct와 union의 차이점
struct는 변수를 하나의 묶음으로 만들어 줍니다. 묶음 하나에 들어 가도 변수는 다른 변수와 같이 들어 갈뿐 자기 자리가 있습니다. 즉, 사탕 4개를 struct라는 주머니에 넣는다면, 사탕은 모두 주머니 안에 들어가도 각각의 사탕은 자기가 차지하는 공간이 있습니다. 그러나 union은 큰 놈 안에 작은 놈이 포개지듯이 들어 갑니다.
그래서 아래와 같이 선언하면 struct로 선언된 struct_byte_t의 크기는 4byte 이지만, union으로 선언된 union_byte_t는 변수가 4개라도 byte 한 개 짜리입니다. 즉, b1, b2, b3, b4 이름만 다른 변수 4개만 있을 뿐 실제 모두 같은 바이트의 주소를 가르키게 됩니다.
typedef unsigned char byte; typedef unsigned int u32; typedef struct { byte b1, b2, b3, b4; } struct_byte_t; typedef union { byte b1, b2, b3, b4; } union_byte_t;
자, 그렇다면 위의 예제가 그림처럼 이해가 되시나요? ^^
typedef struct { byte b1, b2, b3, b4; } size_byte_t; typedef union { u32 size; size_byte_t bytes; } size_data_t;
그래서 메모리에는 아래와 같이 포개지는 꼴이 됩니다.
이런 메모리 구성으로 b1에 값을 넣으면 size 변수의 최 하위 바이트 값이 변경됩니다. size 변수의 최 상위 바이트 값을 변경하려면 b4를 이용하면 되겠지요.
이해를 돕기 위해 예제 하나를 더 올립니다.
#include <stdio.h> typedef unsigned char byte; typedef unsigned int u32; typedef struct { byte b1; byte b2; byte b3; byte b4; } size_byte_t; typedef union { u32 size; size_byte_t bytes; } size_data_t; int main( void){ size_data_t s_size; s_size.size = 0x12345678; printf( "b1=%2x b2=%2x b3=%2x b4=%2x\n", s_size.bytes.b1, s_size.bytes.b2, s_size.bytes.b3, s_size.bytes.b4); return 0; }
어떤 값이 출력될까요?
참고로 char buff[255]와 같이 크기가 정해진 버퍼와도 union을 이용하여 묶어서 사용하면 앞서 정수 값을 계산할 필요도 없어 집니다. 이 예 말고도 리틀엔디언 정수 값을 빅 엔디언으로 바꿀 때도 사용할 수 있구요. 결론으로 짧게 말씀 드린다면, 어떤 고정 크기의 변수에서 특정 부분을 수정하거나 읽어 들일 때 사용하면 편합니다.