構造体の不完全型宣言でメンバを隠蔽する
C言語で、あるモジュールを制御するような構造体があるとする。
どの制御を行うかの選択は上位モジュールに行わせたいが、制御で使用する構造体のメンバは見せたくない、といった場合、構造体の不完全型宣言で解決できる。
以下に等比数列・等差数列を計算するプログラムで、構造体の不完全型宣言を用いた例を書いてみた。
module.h
#ifndef _MODULE_H_INCLUDED_ #define _MODULE_H_INCLUDED_ #include <stdio.h> enum e_type { TYPE_EQUAL_RATIO, /* 等比数列 */ TYPE_EQUAL_DIFF /* 等差数列 */ }; /* * 不完全型宣言 * 構造体のポインタのみ公開する。実体を定義することはできない。 */ typedef struct tag_state *State; State get_state(int val, int k, enum e_type type); void exec_state(State state); #endif
module.c
#include "module.h" /* 等比数列・等差数列の構造体 */ static void func_mul(State); static void func_add(State); /* 状態管理構造体 */ struct tag_state { int index; int val; int k; void (* pfunc_calc)(State); }; /* 等比数列・等差数列の状態管理構造体の実体を定義 */ static struct tag_state equal_ratio_state = { 0, 0, 0, func_mul }; static struct tag_state equal_diff_state = { 0, 0, 0, func_add }; /* 状態管理構造体のハンドルを取得する */ State get_state(int val, int k, enum e_type type) { State state; switch (type) { case TYPE_EQUAL_RATIO: state = &equal_ratio_state; break; case TYPE_EQUAL_DIFF: state = &equal_diff_state; break; default: break; } state->val = val; state->k = k; return state; } /* 処理実行 */ void exec_state(State state) { state->pfunc_calc(state); } /* 等比数列処理 */ static void func_mul(State state) { int result = state->val * state->k; printf("[%d] MUL: %d * %d = %d\n", state->index, state->val, state->k, result); state->index++; state->val = result; } /* 等差数列処理 */ static void func_add(State state) { int result = state->val + state->k; printf("[%d] ADD: %d + %d = %d\n", state->index, state->val, state->k, result); state->index++; state->val = result; }
main.c
#include <stdio.h> #include "module.h" int main() { /* 等比数列・等差数列それぞれのハンドルを取得する */ State eq_ratio = get_state(1, 2, TYPE_EQUAL_RATIO); State eq_diff = get_state(1, 3, TYPE_EQUAL_DIFF); int i; /* 処理実行 */ for (i=0; i<4; i++) { exec_state(eq_ratio); exec_state(eq_diff); } return 0; }
実行結果
$ ./a.out [0] MUL: 1 * 2 = 2 [0] ADD: 1 + 3 = 4 [1] MUL: 2 * 2 = 4 [1] ADD: 4 + 3 = 7 [2] MUL: 4 * 2 = 8 [2] ADD: 7 + 3 = 10 [3] MUL: 8 * 2 = 16 [3] ADD: 10 + 3 = 13
あまりメリットを感じられる例じゃないかも…
参考ページ
http://ch.cri-mw.co.jp/hirase/707.html
K.Maebashi's home page:C言語ヨタ話:その3 「モジュールと命名とヘッダファイルと」