우리가 프로그램을 만들다 보면 다른 곳에서 만든 라이브러리를 가져다 쓰거나, 운영체제에서 제공해주는 API를 사용하는 경우가 대부분입니다.

이러한 라이브러리나 API에서 제공해주는 함수를 사용하려면 그 라이브러리, API에서 제공해주는 자료형을 사용해야 하는 경우가 많습니다. 그런데 이 자료형들은 대부분 구조체가 아닌 포인터들입니다. 그냥 메모리 주소만 담고 있죠. 구조체로 정의되어 있지 않기 때문에 내부가 어떤 멤버들로 구성되어 있는지 알 방법이 없습니다. 이런 것들을 오파크 타입(Opaque Type)이라고 합니다. 대표적인 예가 윈도우 프로그래밍에서의 HANDLE 입니다.

오파크 타입에 대한 설명은 이정도로 하고 실제로 사용하는 방법을 알아보도록 하겠습니다.

먼저 헤더 파일을 2개를 만들도록 하겠습니다.

implement.h: 실제 구현용 헤더 파일

struct opaque_t_ {
    int hello;
    int world;
}

typedef struct opaque_t_ *opaque_t;

opaque.h: 배포용 헤더 파일

typedef void *opaque_t;

void OpaqueInit(opaque_t *opa);
void OpaqueFree(opaque_t *opa);
void SetValue(opaque_t opa);
void PrintValue(opaque_t opa);

이렇게 헤더 파일을 2개로 만든 이유는 실제 구현에 쓰기 위한 헤더 파일과 배포하기 위한 헤더 파일을 나누기 위해서입니다.

실제 구현에 쓰기 위한 헤더파일에는 모든 구조체 정보가 정의되어 있고 배포용 헤더 파일은 opaque_t를 void 포인터로만 정의하고 있습니다. 그래서 배포용 헤더 파일만 받는 쪽은 구조를 알 수 없는 오파크 타입을 이용하게 되는 것입니다.

이제 이 오파크 타입을 처리하는 함수들을 만들어 보겠습니다.

implement.c: 라이브러리 구현

#include <stdio.h>
#include <stdlib.h>
#include "implement.h"


/* 오파크 타입이 구조체 선언이 아닌 포인터이기 때문에 동적 메모리 할당을 해줘야 한다. */
void OpaqueInit(opaque_t *opa)
{
    opaque_t opaque;

    opaque = malloc(sizeof(struct opaque_t_));

    *opa = opaque;
}

/* 동적 메모리 해제 */
void OpaqueFree(opaque_t *opa)
{
    free(*opa);
}

void SetValue(opaque_t opa)
{
    opa->hello = 10;
    opa->world = 20;
}

void PrintValue(opaque_t opa)
{
    printf("hello : %d, world : %d\n", opa->hello, opa->world);
}

OpaqueInit() 함수는 주석에서도 알 수 있듯이 opaque_t가 단순한 구조체 선언이 아니라 void 포인터이기 때문에 실제로 사용하려면 동적 메모리 할당을 해야 사용할 수 있습니다. 그리고 동적 메모리를 할당 했기 때문에 OpaqueFree() 함수로 메모리를 해제 합니다.

SetValue() 함수는 이 opaque_t에 특정 값을 넣고, PrintValue() 함수는 opaque_t의 내용을 화면에 출력해 줍니다. 라이브러리를 구현할 때에는 implement.h를 가지고 있기 때문에 구조체 멤버 변수에 마음대로 접근 할 수 있습니다.

이제 이 opaque.h, implement.h, implement.c를 정적 라이브러리(Static Library)로 만듭니다. 그리고 배포를 할 때에는 implement.h는 빼고, opaque.h와 컴파일된 라이브러리 opaque.lib만 배포하면 됩니다. 그래서 라이브러리를 사용하는 쪽에서는 implement.h 파일이 없기 때문에 opaque_t의 구조를 알 수가 없는 것입니다.

program.c: opaque.lib과 opaque.h을 사용하여 프로그램 작성

#include <opaque.h>


int main()
{
    opaque_t opa;

    OpaqueInit(&opa);

    SetValue(opa);
    PrintValue(opa);

    OpaqueFree(&opa);

    return 0;
}

opaque.lib에서 제공하는 함수들을 사용하여 프로그램을 작성합니다. 이 프로그램을 실행하면 hello : 10, world : 20이 출력될 것입니다.

윈도우 API와 비교하자면 OpaqueInit() 함수와 SetValue() 함수를 합친 것이 CreateFile() 함수이며, OpaqueFree() 함수는 CloseHandle() 함수라고 할 수 있습니다(단 핸들은 메모리 주소가 아닌 핸들 테이블상의 순서이므로 내부적으로 한번 더 처리를 합니다).

opaque-src.zip: Visual C++ 2005에서 컴파일 할 수 있도록 만든 소스입니다.


저작권 안내

이 웹사이트에 게시된 모든 글의 무단 복제 및 도용을 금지합니다.
  • 블로그, 게시판 등에 퍼가는 것을 금지합니다.
  • 비공개 포스트에 퍼가는 것을 금지합니다.
  • 글 내용, 그림을 발췌 및 요약하는 것을 금지합니다.
  • 링크 및 SNS 공유는 허용합니다.

Published

25 March 2007