Entry

プログラミングメモ - C 言語で Pimpl パターンみたいなこと

2010年06月29日

Pimpl パターンは C++ のもの,みたいなイメージがあるけれども,実のところ,これって昔っから C でもやられている方法だったりします。例えば,libsecret というライブラリを作るために,ハンドラとなる構造体のメンバをクライアント(ライブラリの利用者)から隠したいとしますよね。そゆときは,普通こんな風にする。

まず,公開ヘッダとして secret.h を作ります。これは,ライブラリの内部・外部を問わず,誰でも読めるヘッダです。同時に,インターフェイスとして,ハンドラの初期化関数と解放関数を宣言しています。

#ifndef SECRET_H__INCLUDED
#define SECRET_H__INCLUDED

extern struct secret_t_;
typedef struct secret_t_ secret_t;

int secret_init(secret_t **hnd);
int secret_finalize(secret_t *hnd);

#endif  /* SECRET_H__INCLUDED */

ハンドラとなる構造体を extern 宣言していることに注目しておいてください。次に,ライブラリ内部でしか読めないヘッダ local.h を作ります。

#ifndef LOCAL_H__INCLUDED
#define LOCAL_H__INCLUDED

#include "secret.h"

struct secret_t_ {
    int foo_member;
    int bar_member;
    int baz_member;
};

#endif  /* LOCAL_H__INCLUDED */

ここにハンドラとなる構造体(secret_t)の中身を書きます。ローカルでしか読めないので,メンバがどうなっているのか,クライアントからは分かりません。

最後に,初期化関数と解放関数を secret.c で実装します。

#include <stdlib.h>
#include "local.h"

int
secret_init(secret_t **hnd) {
    secret_t *tmp;

    if ((tmp = malloc(sizeof(secret_t))) == NULL) {
        return -1;
    }
    /* initialize */
    tmp->foo_member = 0;
    tmp->bar_member = 0;
    tmp->baz_member = 0;
    *hnd = tmp;

    return 0;
}

int
secret_finalize(secret_t *hnd) {
    if (hnd != NULL) {
        free(hnd);
    }
}

使うときはこんな風に使うことになる。

#include <secret.h>

int
main(int argc, char *argv[]) {
    secret_t *hnd;

    secret_init(&hnd);
    /* hnd を使った処理 */
    secret_finalize(hnd);

    return 0;
}

結局,コードの依存関係をリンク時まで引き延ばせば,Pimpl パターンみたいなこと(厳密には一緒ではない)ができるというワケ。ま,ただそんだけなんですけどね。「C でライブラリを作って」といったら,メンバむき出しで書く人を見かけたから,ちょっとネタにしてみました。

Trackback
Trackback URL:
Ads
About
Search This Site
Ads
Categories
Recent Entries
Log Archive
Syndicate This Site
Info.
クリエイティブ・コモンズ・ライセンス
Movable Type 3.36
Valid XHTML 1.1!
Valid CSS!
ブログタイムズ

© 2003-2012 AIAN