공용체(union)을 이용한 다중 멤버 변수 이름 지정
Study/C/C++ 2009. 1. 24. 13:54 |공용체란 C언어 문법 책 뒷쪽에, 구조체(structure) 다음에 꼽사리로 나오는 데이터 구조.
예를 들어, 아래와 같은 공용체가 정의되어있다고 하자.
이 경우, 이 공용체는 전체 8바이트의 크기를 갖는다. 이 8바이트 중에서 첫 번째 바이트는 a 변수가 사용하고, 처음 네 개의 바이트는 b가 사용하고, 처음부터 끝까지 여덟 바이트는 c가 사용한다. 즉, 세 멤버 변수 a, b, c 는 중첩된 메모리 공간을 같이 사용한다. 그러므로, a 변수에 값을 저장하면, b와 c에 저장된 값은 전혀 다른 값으로 바뀌게 된다.
"도대체 이런 구조를 왜 써야할까???" 하는 의문을 바로 몇 달전 C 프로그래밍을 가르치면서 다시금 떠올렸었다.
그러다가 OpenCV 책을 번역하면서 발견한, union의 효과적인 사용 예를 기록해보려고 한다.
OpenCV의 행렬 구조체의 정의는 다음과 같다.
CvMat 라는 구조체 내부에 union이 두루 사용된 것을 볼 수 있다. 먼저 아래쪽 두 개의 union을 보면 rows 와 height 두 개를 union으로 감싸고 있다. 이 경우, rows 와 height 는 같은 메모리 공간을 지칭하는 변수가 된다. 즉, 행렬의 행의 크기를 나타내는 값을 rows 라는 변수로도 접근할 수 있고, height 라는 변수로도 접근할 수가 있는 것이다. 이건, 꽤 괜찮다. ^^;
두 번째, 위 구조체 정의 중간에 있는 data 라는 이름을 할당한 union은 5 가지 종류의 포인터 변수를 가지고 있는데, 이 또한 꽤 그럴싸하다. 어차피 포인터 형 변수라면 항상 4바이트(win32 환경의 경우)를 갖게 되니까 data 변수는 결과적으로 4바이트를 갖는다. 그런데 data.ptr 을 사용할 수도 있고, data.s, data.i, data.fl, data.db 를 사용할 수도 있다. 즉, CvMat 행렬이 실제 저장하고 있는 값이 무슨 타입이냐에 따라 실제 데이터가 저장된 메모리 공간을 가리키는 변수를 선택적으로 사용할 수 있는 것이다. 그러면 뭐가 좋을까??? 포인터 연산을 통해 주변 원소로 이동할 때 캐스팅을 따로 하지 않아도 되는 장점이 생긴다. (물론 주의해서 사용해야 하는 점은 존재한다.) 음... 어려울려나?? 암튼 좋은거다. ^^;
암튼, union을 사용해서 도움이 되는 예제를 처음 보다시피하여 기록해보았다. 도움이 될라나.. 흠..
예를 들어, 아래와 같은 공용체가 정의되어있다고 하자.
typedef union _data { char a; int b; float c; } data;
이 경우, 이 공용체는 전체 8바이트의 크기를 갖는다. 이 8바이트 중에서 첫 번째 바이트는 a 변수가 사용하고, 처음 네 개의 바이트는 b가 사용하고, 처음부터 끝까지 여덟 바이트는 c가 사용한다. 즉, 세 멤버 변수 a, b, c 는 중첩된 메모리 공간을 같이 사용한다. 그러므로, a 변수에 값을 저장하면, b와 c에 저장된 값은 전혀 다른 값으로 바뀌게 된다.
"도대체 이런 구조를 왜 써야할까???" 하는 의문을 바로 몇 달전 C 프로그래밍을 가르치면서 다시금 떠올렸었다.
그러다가 OpenCV 책을 번역하면서 발견한, union의 효과적인 사용 예를 기록해보려고 한다.
OpenCV의 행렬 구조체의 정의는 다음과 같다.
typedef struct CvMat { int type; int step; int* refcount; int hdr_refcount; union { uchar* ptr; short* s; int* i; float* fl; double* db; } data; union { int rows; int height; }; union { int cols; int width; }; } CvMat;
CvMat 라는 구조체 내부에 union이 두루 사용된 것을 볼 수 있다. 먼저 아래쪽 두 개의 union을 보면 rows 와 height 두 개를 union으로 감싸고 있다. 이 경우, rows 와 height 는 같은 메모리 공간을 지칭하는 변수가 된다. 즉, 행렬의 행의 크기를 나타내는 값을 rows 라는 변수로도 접근할 수 있고, height 라는 변수로도 접근할 수가 있는 것이다. 이건, 꽤 괜찮다. ^^;
두 번째, 위 구조체 정의 중간에 있는 data 라는 이름을 할당한 union은 5 가지 종류의 포인터 변수를 가지고 있는데, 이 또한 꽤 그럴싸하다. 어차피 포인터 형 변수라면 항상 4바이트(win32 환경의 경우)를 갖게 되니까 data 변수는 결과적으로 4바이트를 갖는다. 그런데 data.ptr 을 사용할 수도 있고, data.s, data.i, data.fl, data.db 를 사용할 수도 있다. 즉, CvMat 행렬이 실제 저장하고 있는 값이 무슨 타입이냐에 따라 실제 데이터가 저장된 메모리 공간을 가리키는 변수를 선택적으로 사용할 수 있는 것이다. 그러면 뭐가 좋을까??? 포인터 연산을 통해 주변 원소로 이동할 때 캐스팅을 따로 하지 않아도 되는 장점이 생긴다. (물론 주의해서 사용해야 하는 점은 존재한다.) 음... 어려울려나?? 암튼 좋은거다. ^^;
암튼, union을 사용해서 도움이 되는 예제를 처음 보다시피하여 기록해보았다. 도움이 될라나.. 흠..
'Study > C/C++' 카테고리의 다른 글
배치 파일을 이용하여 Visual C++ 프로젝트 일괄 빌드하기 (0) | 2017.07.21 |
---|---|
C언어에서 실수값을 정수값으로 변환하는 방법 (자름, 반올림) (2) | 2009.02.12 |
double atan2(double y, double x) 사용법 (0) | 2008.11.30 |
유니코드의 역사, 인코딩, 프로그래밍 (0) | 2008.10.01 |
공백 클래스(empty class)와 바이트 패딩(byte padding) (0) | 2008.08.28 |