728x90

UNION

C에서는 공용체라 부르는 특수한 타입이 있다. 공용체의 멤버로 선언된 변수들은 메모리 어드레스를 공유하게 된다. 어찌보면 별 필요없는 기능이라고 생각될 수도 있지만 메시지를 만들어 데이터를 읽고 쓰는데는 아주 유용한 기능이다.

선언 및 사용

union의 선언 방법은 struct와 동일하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
union simple_message {
int a;
int b;
};
 
int main(int argc, char **argv)
{
union simple_message smessage;
smessage.a = 1;
 
printf("smessage.a: %dn", smessage.a);
printf("smessage.b: %dn", smessage.b);
}

출력 결과를 보면 공용체 smessage의 멤버 a의 값과 b의 값이 동일한 것을 볼 수 있다. 멤버 a의 값이 변경된 것이 b에도 적용된 것 처럼 보이지만 사실은 공용체 멤버 a와 b가 동일한 메모리 주소를 공유하고 있는 것이다.

Example


위와 같은 데이터를 읽고 쓴다고 하자. 4 bytes 데이터 이므로 int 값에 bit 연산으로 데이터를 채워 넣는 방법을 쓸 수도 있지만 가독성이 떨어지며 코드길이가 길어져 한참후에 코드를 들여다 봤을 때 이해하는 것이 불가능해 질 수도 있다. 하지만 union을 사용하면 데이터를 다루기도 쉽고 이해하기도 편리하다는 것을 깨닫게 될 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <linux/types.h>
#include <memory.h>
 
struct regdata {
 __u16 opcode:4;
 __u16 prtaddr:5;
 __u16 regaddr:5;
 __u16 ta:2;
 __u16 data;
} __attribute__((packed));
 
union data {
 struct regdata reg0;
 __u32 rdata;
};
 
int main(int argc, char** argv)
{
 union data message;
 
 memset(&message, 0x0, sizeof(union data));
 message.reg0.opcode = 0x4;
 message.reg0.regaddr = 0x3;
 message.reg0.data = 0xE8A3;
 
 printf("message: %08xn", message.rdata);
 
 return 0;
}

실행결과는 message: e8a30604 이다. intel 시스템일 경우 little endian을 사용함으로 big endian으로 읽어보면 제대로데이터가 들어간 것을 알 수 있다.


728x90

+ Recent posts