公開しない関数
こんな感じのCソースがあった。本質部分を再構成すると、
foo.h
#ifndef FOO_H_INCLUDED #define FOO_H_INCLUDED #ifdef USE_FOO_H_PRIVATE #define PRIVATE static #else #define PRIVATE /##/ #endif void bar(void); PRIVATE void zot(void); #undef PRIVATE #endif /* FOO_H_INCLUDED */
foo.c
#define USE_FOO_H_PRIVATE #include "foo.h" void bar(void) { zot(); } static void zot(void) { }
user.c
#include "foo.h" int main(void) { bar(); /* zot(); *//* the function zot is static in foo.c, so compile error occurs. */ return 0; }
意図は、公開されている関数barと静的関数zotのプロトタイプ宣言を行っているヘッダファイルを
barの利用者user.cでも共通にインクルードできるようにしようとしていると思われる。
しかし妙な技巧に走っている割に問題点がいろいろあると思う。
まず、USE_FOO_H_PRIVATEが定義されていない時のPRIVATEマクロの定義は処理系依存の技法である。
また、//によるコメントアウトはC99では使えるがC89では規格外である。
そして、難読化しかねない条件コンパイルの多用は避けるべきとの考え方もある。
foo.cの中のみでしか使えない関数zotのプロトタイプ宣言を公開するヘッダに書く必要はない。
PRIVATEと銘打ったものをわざわざ公開するヘッダファイルに載せるのは矛盾する行為であろう。
foo.h
#ifndef FOO_H_INCLUDED #define FOO_H_INCLUDED void bar(void); #endif /* FOO_H_INCLUDED */
foo.c
#include "foo.h" static void zot(void); void bar(void) { zot(); } static void zot(void) { }
直にfoo.cに書くだけでいい。foo.hの見通しがよくなるし、foo.cも特に複雑になるわけでない。
もし、zotを静的関数にせず、foo.c以外にbaz.c中の公開関数bazでもzotを使い、
かつ、それ以外のソースに対してはzotを非公開にしたい、というような要望があるなら、
foo.h
#ifndef FOO_H_INCLUDED #define FOO_H_INCLUDED void bar(void); void baz(void); #endif /* FOO_H_INCLUDED */
foo_private.h
#ifndef FOO_PRIVATE_H_INCLUDED #define FOO_PRIVATE_H_INCLUDED void zot(void); #endif /* FOO_PRIVATE_H_INCLUDED */
foo.c
#include "foo.h" #include "foo_private.h" void bar(void) { zot(); } void zot(void) { }
baz.c
#include "foo.h" #include "foo_private.h" void baz(void) { zot(); }
user.h
#include "foo.h" int main(void) { bar(); baz(); /* zot(); *//* compiler warns of missing prototype. */ return 0; }
のように、公開するものと非公開のもののヘッダファイルを分ければいい。
条件コンパイルするくらいならファイルを分けた方が見やすい。