[C, C++] 공용체(union) 개념과 통신에서의 사용 이유

서론

아마 c언어를 배웠던 사람이라도 이 union은 모르는 사람이 많을 것 같다. 내가 그랬고 내 주변도 그랬다. 그런데 임베디드를 개발하면서 남들이 작성한 코드에 union이 있었고 코드 분석을 위해서 알아야 했다. 그리고 union의 편리성을 알고 나서 나조차도 쓰게 되었다.

union

union은 struct와 유사하지만 union의 변수 중 가장 큰 변수의 메모리를 모든 변수가 공유한다는 점에서 다르다.

같은 변수를 가지는 struct와 union의 size를 출력해보면 아래와 같이 결과가 다른것을 확인할 수 있다.

typedef struct sizeTest_struct
{
    int a;	// 4byte
    double b;	// 8byte
}sizeTest_struct;

typedef union sizeTest_union
{
    int a;
    double b;
}sizeTest_union;

int main()
{
    sizeTest_struct s;
    sizeTest_union u;
    printf("struct size : %d\r\n", sizeof(s));	// 16
    printf("union size : %d\r\n", sizeof(u));	// 8
}

구조체는 가장 큰 변수를 기준으로 메모리를 할당한다. 따라서 위 sizeTest_struct는 double이 8바이트, int도 double을 따라서 8바이트로 할당되어 총사이즈는 16바이트가 출력된다. 그러나 sizeTest_union은 가장 큰 변수인 b가 double이므로 8바이트를 모든 변수가 공유하게 되어 총 사이즈는 8바이트가 출력된다. 변수들이 메모리를 공유하는건 변수들에 값을 넣어보면 바로 확인이 가능하다. 아래와 같이 union의 변수 a와 b에 0을 쓰면 둘 다 0을 출력함을 볼 수 있다.

#include <stdio.h>

typedef union test_union
{
    int a;
    int b;
}test_union;

int main()
{
    test_union u = {0, 0};
    printf("u.a : %d, u.b : %d\r\n", u.a, u.b);	// u.a : 0, u.b : 0

그리고 a에 10을 쓰면 a는 물론 b도 10을 출력함을 볼 수 있다.

#include <stdio.h>

typedef union test_union
{
    int a;
    int b;
}test_union;

int main()
{
    test_union u = {0, 0};
    printf("u.a : %d, u.b : %d\r\n", u.a, u.b);	// u.a : 0, u.b : 0
    
    u.a = 10;
    printf("u.a : %d, u.b : %d\r\n", u.a, u.b);	// u.a : 10, u.b : 10
}

다시 b에 20을 쓰면 a와 b 모두 20을 출력함을 볼 수 있다.

#include <stdio.h>

typedef union test_union
{
    int a;
    int b;
}test_union;

int main()
{
    test_union u = {0, 0};
    printf("u.a : %d, u.b : %d\r\n", u.a, u.b);	// u.a : 0, u.b : 0
    
    u.a = 10;
    printf("u.a : %d, u.b : %d\r\n", u.a, u.b);	// u.a : 10, u.b : 10
    
    u.b = 20;
    printf("u.a : %d, u.b : %d\r\n", u.a, u.b);	// u.a : 20, u.b : 20
}

union 활용

union은 변수들이 메모리를 공유한다는 특징 때문에 통신에서 아주 편리하게 이용된다.

실제 동작하지 않는 예제코드

typedef union comm
{
    char buffer[4];
    struct {
        char version;
        char header;
        char length;
        char address;
    }segment;
}comm;

int main()
{
    MessageSend(comm.buffer[0]);
    MessageReceive(comm.segment.version, comm.segment.header, comm.segment.length, comm.segment.address);
}

통신을 위해서는 데이터를 주고받아야 한다. 그리고 데이터는 패킷 단위로 묶어서 보내게 되는데, 단순히 보내는 건 쉽지만 받는 입장에서는 덩어리로 온 데이터를 받아서 분해하고 다시 묶어서 보내기가 여간 까다롭다. 정확히는 까다롭다기보다는 귀찮다. 그런데 위와 같이 공용체를 사용한다면 보낼 때는 buffer로 한 번에 보내고 받을 때는 struct의 변수들로 각각 받을 수 있어서 편리하다. 이때문에 통신에서 union을 접할 수 있다.

그러나 최근에는 임베디드통신에서도 여러 플랫폼과의 호환을 위해서 이더넷, REST, JSON과 같은 키워드가 점점 늘어나는걸 체감하고있다.

Leave a Comment